Skip to content

Commit 2adadbc

Browse files
michel2323claude
andcommitted
Root oneMKL FFT descriptor arrays across the C call
The DFT wrappers passed pointer(lengths) / pointer(strides) to the descriptor create/set calls. A raw Ptr does not keep the backing vector alive, so the GC could collect it mid-call and oneMKL would read garbage dimensions/strides, failing commit with FFT_INVALID_DESCRIPTOR or a SIGFPE depending on heap reuse. Pass the arrays themselves so ccall roots them for the duration of the call (lib/mkl/fft.jl). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 6aa93e0 commit 2adadbc

1 file changed

Lines changed: 19 additions & 28 deletions

File tree

lib/mkl/fft.jl

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -93,23 +93,22 @@ function _create_descriptor(sz::NTuple{N,Int}, T::Type, complex::Bool) where {N}
9393
prec = T<:Float64 || T<:ComplexF64 ? ONEMKL_DFT_PRECISION_DOUBLE : ONEMKL_DFT_PRECISION_SINGLE
9494
dom = complex ? ONEMKL_DFT_DOMAIN_COMPLEX : ONEMKL_DFT_DOMAIN_REAL
9595
desc_ref = Ref{onemklDftDescriptor_t}()
96-
# Create descriptor for the full array dimensions. `lengths` must stay rooted
97-
# across the ccall: oneMKL copies the dimensions out of `pointer(lengths)`, and
98-
# without GC.@preserve the array can be collected first, leaving the descriptor
99-
# with garbage dimensions (commit then fails with FFT_INVALID_DESCRIPTOR).
96+
# Create descriptor for the full array dimensions
10097
lengths = collect(Int64, sz)
101-
st = GC.@preserve lengths (length(lengths) == 1 ?
102-
onemklDftCreate1D(desc_ref, prec, dom, lengths[1]) :
103-
onemklDftCreateND(desc_ref, prec, dom, length(lengths), pointer(lengths)))
98+
# NB: pass the arrays themselves to the ccall wrappers (NOT `pointer(...)`) so they
99+
# are rooted for the duration of the call; passing a raw Ptr lets the GC collect the
100+
# vector mid-call, which made MKL read garbage lengths/strides and fail `commit` with
101+
# invalid_descriptor_exception or a SIGFPE, depending on heap reuse.
102+
st = length(lengths) == 1 ? onemklDftCreate1D(desc_ref, prec, dom, lengths[1]) : onemklDftCreateND(desc_ref, prec, dom, length(lengths), lengths)
104103
st == 0 || error("onemkl DFT create failed (status $st)")
105104
desc = desc_ref[]
106105
# Do not program descriptor scaling; we'll perform inverse normalization manually.
107106
# Set placement explicitly based on plan type later
108-
# Use the task-local cached SYCL queue wrapping the global Level Zero queue, like the
109-
# other oneMKL wrappers do. Creating fresh syclContext/syclQueue objects per plan is
110-
# unsound: once they become garbage their finalizers (syclQueueDestroy etc.) tear down
111-
# SYCL runtime state for the still-in-use underlying queue, corrupting later DFT
112-
# commits and crashing at process exit.
107+
# Use the task-local cached SYCL queue wrapping the global Level Zero queue, like
108+
# the other oneMKL wrappers do. Creating fresh syclContext/syclQueue objects per
109+
# plan is unsound: once they become garbage their finalizers (syclQueueDestroy etc.)
110+
# tear down SYCL runtime state for the still-in-use underlying queue, corrupting
111+
# later DFT commits (SIGFPE) and crashing at process exit.
113112
ze_ctx = oneAPI.context(); ze_dev = oneAPI.device()
114113
q = oneAPI.sycl_queue(oneAPI.global_queue(ze_ctx, ze_dev))
115114
return desc, q
@@ -132,10 +131,8 @@ function plan_fft(X::oneAPI.oneArray{T,N}, region) where {T<:Union{ComplexF32,Co
132131
strides[i+1] = prod
133132
prod *= size(X,i)
134133
end
135-
GC.@preserve strides begin
136-
onemklDftSetValueInt64Array(desc, ONEMKL_DFT_PARAM_FWD_STRIDES, pointer(strides), length(strides))
137-
onemklDftSetValueInt64Array(desc, ONEMKL_DFT_PARAM_BWD_STRIDES, pointer(strides), length(strides))
138-
end
134+
onemklDftSetValueInt64Array(desc, ONEMKL_DFT_PARAM_FWD_STRIDES, strides, length(strides))
135+
onemklDftSetValueInt64Array(desc, ONEMKL_DFT_PARAM_BWD_STRIDES, strides, length(strides))
139136
end
140137
stc = onemklDftCommit(desc, q); stc == 0 || error("commit failed ($stc)")
141138
return cMKLFFTPlan{T,MKLFFT_FORWARD,false,N,R,Nothing}(desc,q,size(X),size(X),false,reg,nothing,nothing)
@@ -153,10 +150,8 @@ function plan_bfft(X::oneAPI.oneArray{T,N}, region) where {T<:Union{ComplexF32,C
153150
@inbounds for i in 1:N
154151
strides[i+1]=prod; prod*=size(X,i)
155152
end
156-
GC.@preserve strides begin
157-
onemklDftSetValueInt64Array(desc, ONEMKL_DFT_PARAM_FWD_STRIDES, pointer(strides), length(strides))
158-
onemklDftSetValueInt64Array(desc, ONEMKL_DFT_PARAM_BWD_STRIDES, pointer(strides), length(strides))
159-
end
153+
onemklDftSetValueInt64Array(desc, ONEMKL_DFT_PARAM_FWD_STRIDES, strides, length(strides))
154+
onemklDftSetValueInt64Array(desc, ONEMKL_DFT_PARAM_BWD_STRIDES, strides, length(strides))
160155
end
161156
stc = onemklDftCommit(desc, q); stc == 0 || error("commit failed ($stc)")
162157
return cMKLFFTPlan{T,MKLFFT_INVERSE,false,N,R,Nothing}(desc,q,size(X),size(X),false,reg,nothing,nothing)
@@ -176,10 +171,8 @@ function plan_fft!(X::oneAPI.oneArray{T,N}, region) where {T<:Union{ComplexF32,C
176171
@inbounds for i in 1:N
177172
strides[i+1]=prod; prod*=size(X,i)
178173
end
179-
GC.@preserve strides begin
180-
onemklDftSetValueInt64Array(desc, ONEMKL_DFT_PARAM_FWD_STRIDES, pointer(strides), length(strides))
181-
onemklDftSetValueInt64Array(desc, ONEMKL_DFT_PARAM_BWD_STRIDES, pointer(strides), length(strides))
182-
end
174+
onemklDftSetValueInt64Array(desc, ONEMKL_DFT_PARAM_FWD_STRIDES, strides, length(strides))
175+
onemklDftSetValueInt64Array(desc, ONEMKL_DFT_PARAM_BWD_STRIDES, strides, length(strides))
183176
end
184177
stc = onemklDftCommit(desc, q); stc == 0 || error("commit failed ($stc)")
185178
cMKLFFTPlan{T,MKLFFT_FORWARD,true,N,R,Nothing}(desc,q,size(X),size(X),false,reg,nothing,nothing)
@@ -197,10 +190,8 @@ function plan_bfft!(X::oneAPI.oneArray{T,N}, region) where {T<:Union{ComplexF32,
197190
@inbounds for i in 1:N
198191
strides[i+1]=prod; prod*=size(X,i)
199192
end
200-
GC.@preserve strides begin
201-
onemklDftSetValueInt64Array(desc, ONEMKL_DFT_PARAM_FWD_STRIDES, pointer(strides), length(strides))
202-
onemklDftSetValueInt64Array(desc, ONEMKL_DFT_PARAM_BWD_STRIDES, pointer(strides), length(strides))
203-
end
193+
onemklDftSetValueInt64Array(desc, ONEMKL_DFT_PARAM_FWD_STRIDES, strides, length(strides))
194+
onemklDftSetValueInt64Array(desc, ONEMKL_DFT_PARAM_BWD_STRIDES, strides, length(strides))
204195
end
205196
stc = onemklDftCommit(desc, q); stc == 0 || error("commit failed ($stc)")
206197
cMKLFFTPlan{T,MKLFFT_INVERSE,true,N,R,Nothing}(desc,q,size(X),size(X),false,reg,nothing,nothing)

0 commit comments

Comments
 (0)