Skip to content

Commit

Permalink
Add a generic attribute getter/setter, and make compatible with CPU Ptr.
Browse files Browse the repository at this point in the history
  • Loading branch information
maleadt committed Jan 29, 2020
1 parent 9a80e50 commit 559008b
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 17 deletions.
38 changes: 28 additions & 10 deletions src/memory.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Raw memory management

export Mem, memory_type, is_managed
export Mem, attribute, attribute!, memory_type, is_managed

module Mem

Expand Down Expand Up @@ -346,16 +346,34 @@ total_memory() = Mem.info()[2]

## pointer attributes

@enum_without_prefix CUmemorytype CU_
"""
attribute(ptr::Union{Ptr,CuPtr}, attr)
function memory_type(x)
dat = Ref{CUmemorytype}()
cuPointerGetAttribute(dat, CU_POINTER_ATTRIBUTE_MEMORY_TYPE, x)
return CUmemorytype(dat[])
Returns information about the pointer.
"""
function attribute(ptr::Union{Ptr{T},CuPtr{T}}, attr::CUpointer_attribute) where {T}
ptr = reinterpret(CuPtr{T}, ptr)
data_ref = Ref{Cint}()
cuPointerGetAttribute(data_ref, attr, ptr)
return data_ref[]
end

function is_managed(x)
dat = Ref{UInt32}()
cuPointerGetAttribute(dat, CU_POINTER_ATTRIBUTE_IS_MANAGED, x)
return convert(Bool, dat[])
"""
attribute!(ptr::Union{Ptr,CuPtr}, attr, val)
Sets an attribute about a pointer to `val`.
"""
function attribute!(ptr::Union{Ptr{T},CuPtr{T}}, attr::CUpointer_attribute, val) where {T}
ptr = reinterpret(CuPtr{T}, ptr)
cuPointerSetAttribute(Ref(val), attr, ptr)
return
end

@enum_without_prefix CUpointer_attribute CU_

# some common attributes

@enum_without_prefix CUmemorytype CU_
memory_type(x) = CUmemorytype(attribute(x, POINTER_ATTRIBUTE_MEMORY_TYPE))

is_managed(x) = convert(Bool, attribute(x, POINTER_ATTRIBUTE_IS_MANAGED))
30 changes: 23 additions & 7 deletions test/memory.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,38 @@ for srcTy in [Mem.Device, Mem.Host, Mem.Unified],

# test the memory-type attribute
if isa(src, Mem.Device)
@test CUDAdrv.memory_type(src.ptr) == CUDAdrv.MEMORYTYPE_DEVICE
@test CUDAdrv.memory_type(typed_pointer(src, T)) == CUDAdrv.MEMORYTYPE_DEVICE
elseif isa(src, Mem.Host)
@test CUDAdrv.memory_type(convert(Ptr{T}, src)) == CUDAdrv.MEMORYTYPE_HOST
elseif isa(src, Mem.Unified)
# unified memory can reside in either place
# FIXME: does this depend on the current migration, or on the configuration?
@test CUDAdrv.memory_type(convert(CuPtr{T}, src)) == CUDAdrv.MEMORYTYPE_HOST ||
CUDAdrv.memory_type(convert(CuPtr{T}, src)) == CUDAdrv.MEMORYTYPE_DEVICE ||
@test CUDAdrv.memory_type(convert(CuPtr{T}, src)) == CUDAdrv.memory_type(convert(Ptr{T}, src))
end

# test the is-managed attribute
if isa(src, Mem.Device)
@test !CUDAdrv.is_managed(typed_pointer(src, T))
@test !CUDAdrv.is_managed(src.ptr)
end
if isa(src, Mem.Unified)
@test CUDAdrv.is_managed(typed_pointer(src, T))
@test CUDAdrv.is_managed(src.ptr)
@test CUDAdrv.is_managed(convert(Ptr{T}, src))
@test CUDAdrv.is_managed(convert(CuPtr{T}, src))
else
@test !CUDAdrv.is_managed(typed_pointer(src, T))
end

Mem.free(src)
Mem.free(dst)
end

# pointer attributes
let
src = Mem.alloc(Mem.Device, nb)

attribute!(typed_pointer(src, T), CUDAdrv.POINTER_ATTRIBUTE_SYNC_MEMOPS, 0)

Mem.free(src)
end

# asynchronous operations
let
src = Mem.alloc(Mem.Device, nb)
Expand All @@ -84,10 +98,12 @@ let

# get the CPU address and copy some data
cpu_ptr = convert(Ptr{T}, src)
@test CUDAdrv.memory_type(cpu_ptr) == CUDAdrv.MEMORYTYPE_HOST
unsafe_copyto!(cpu_ptr, pointer(data), N)

# get the GPU address and construct a fake device buffer
gpu_ptr = convert(CuPtr{Cvoid}, src)
@test CUDAdrv.memory_type(gpu_ptr) == CUDAdrv.MEMORYTYPE_HOST
gpu_obj = Mem.alloc(Mem.Device, nb)
dst = similar(gpu_obj, gpu_ptr)
Mem.free(gpu_obj)
Expand Down

0 comments on commit 559008b

Please sign in to comment.