Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-pin variable sized memory #2599

Merged
merged 2 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions lib/cudadrv/memory.jl
Original file line number Diff line number Diff line change
Expand Up @@ -659,9 +659,14 @@ end

const __pin_lock = ReentrantLock()

struct PinnedObject
ref::WeakRef
size::Int # memory size in bytes
end

# - IdDict does not free the memory
# - WeakRef dict does not unique the key by objectid
const __pinned_objects = Dict{Tuple{CuContext,Ptr{Cvoid}}, WeakRef}()
const __pinned_objects = Dict{Tuple{CuContext,Ptr{Cvoid}}, PinnedObject}()

function pin(a::AbstractArray)
ctx = context()
Expand All @@ -670,10 +675,15 @@ function pin(a::AbstractArray)
Base.@lock __pin_lock begin
# only pin an object once per context
key = (ctx, convert(Ptr{Nothing}, ptr))
if haskey(__pinned_objects, key) && __pinned_objects[key].value !== nothing
return nothing
if haskey(__pinned_objects, key) && __pinned_objects[key].ref.value !== nothing
if sizeof(a) == __pinned_objects[key].size
return nothing
else
# if the object size has changed, unpin it first; it will be re-pinned with the new size
__unpin(ptr, ctx)
end
end
__pinned_objects[key] = WeakRef(a)
__pinned_objects[key] = PinnedObject(WeakRef(a), sizeof(a))
end

__pin(ptr, sizeof(a))
Expand Down
14 changes: 14 additions & 0 deletions test/core/cudadrv.jl
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,20 @@ if attribute(device(), CUDA.DEVICE_ATTRIBUTE_HOST_REGISTER_SUPPORTED) != 0
dA = CUDA.rand(UInt8, 512)
copyto!(dA, hA)
copyto!(hA, dA)

# memory copies with resized pinned memory (used to fail with CUDA_ERROR_INVALID_VALUE)
dA = rand(Float32, 100)
hA = Array(dA)
@test !CUDA.is_pinned(pointer(hA))
for n ∈ 100:2000
resize!(dA, n)
resize!(hA, n)
dA .= n
CUDA.pin(hA)
@test CUDA.is_pinned(pointer(hA))
copyto!(hA, dA)
copyto!(dA, hA)
end
end

end
Expand Down
Loading