From 55c15adc9acded2194819efc967a6b1b79d8de1e Mon Sep 17 00:00:00 2001 From: Samuel Powell Date: Thu, 4 Jan 2018 12:09:37 +0000 Subject: [PATCH 1/3] Permit copying views of arrays with unit stride --- src/array.jl | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/array.jl b/src/array.jl index 08bfb03..b5d8171 100644 --- a/src/array.jl +++ b/src/array.jl @@ -167,6 +167,41 @@ const copyfun = VERSION >= v"0.7.0-DEV.3057" ? :(copyto!) : :(copy!) Mem.transfer!(dst.buf, src.buf, length(src) * sizeof(T)) return dst end + + """ + $copyfun{T}(dst::CuArray{T}, src::SubArray{T,N,A,I,true}) + + Copy an array view from a host array `src` to a device array `dst` in place. Both arrays + should have an equal length, and the stide of the view must be unity in all dimensions. + """ + function Base.$copyfun(dst::CuArray{T}, src::SubArray{T,N,A,I,true}) where T + if length(dst) != length(src) + throw(ArgumentError("Inconsistent array length.")) + end + if any(strides(src) .!= 1) + throw(ArgumentError("Transfers to an array view require unit stride.")) + end + Mem.upload!(dst.buf, pointer(src), length(src) * sizeof(T)) + return dst + end + + """ + $copyfun{T}(dst::SubArray{T,N,A,I,true}, src::CuArray{T}) + + Copy an array from a device array `src` to a host array view `dst` in place. Both arrays + should have an equal length, and the stride of the view must be unity in all dimensions. + """ + function Base.$copyfun(dst::SubArray{T,N,A,I,true}, src::CuArray{T}) where T + if length(dst) != length(src) + throw(ArgumentError("Inconsistent array length.")) + end + if any(strides(dst) .!= 1) + throw(ArgumentError("Transfers to an array view require unit stride.")) + end + Mem.download!(pointer(dst), src.buf, length(src) * sizeof(T)) + return dst + end + end From 0f15f4ddae2118f7179b68bc7bb8dd2212ea00ea Mon Sep 17 00:00:00 2001 From: Samuel Powell Date: Thu, 4 Jan 2018 12:11:49 +0000 Subject: [PATCH 2/3] Capture all type parameters --- src/array.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array.jl b/src/array.jl index b5d8171..f92c50e 100644 --- a/src/array.jl +++ b/src/array.jl @@ -174,7 +174,7 @@ const copyfun = VERSION >= v"0.7.0-DEV.3057" ? :(copyto!) : :(copy!) Copy an array view from a host array `src` to a device array `dst` in place. Both arrays should have an equal length, and the stide of the view must be unity in all dimensions. """ - function Base.$copyfun(dst::CuArray{T}, src::SubArray{T,N,A,I,true}) where T + function Base.$copyfun(dst::CuArray{T}, src::SubArray{T,N,A,I,true}) where {T,N,A,I} if length(dst) != length(src) throw(ArgumentError("Inconsistent array length.")) end @@ -191,7 +191,7 @@ const copyfun = VERSION >= v"0.7.0-DEV.3057" ? :(copyto!) : :(copy!) Copy an array from a device array `src` to a host array view `dst` in place. Both arrays should have an equal length, and the stride of the view must be unity in all dimensions. """ - function Base.$copyfun(dst::SubArray{T,N,A,I,true}, src::CuArray{T}) where T + function Base.$copyfun(dst::SubArray{T,N,A,I,true}, src::CuArray{T}) where {T,N,A,I} if length(dst) != length(src) throw(ArgumentError("Inconsistent array length.")) end From 10d2cbaa27bb80e66e7330c5469b24924200f57e Mon Sep 17 00:00:00 2001 From: Samuel Powell Date: Mon, 8 Jan 2018 21:04:48 +0000 Subject: [PATCH 3/3] Restrict to dense contiguous views, add tests --- src/array.jl | 26 +++++++++++++++++--------- test/array.jl | 27 +++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/array.jl b/src/array.jl index f92c50e..473edde 100644 --- a/src/array.jl +++ b/src/array.jl @@ -169,39 +169,47 @@ const copyfun = VERSION >= v"0.7.0-DEV.3057" ? :(copyto!) : :(copy!) end """ - $copyfun{T}(dst::CuArray{T}, src::SubArray{T,N,A,I,true}) + $copyfun{T}(dst::CuArray{T}, src::SubArray{T,N,<:DenseArray,I,true}) Copy an array view from a host array `src` to a device array `dst` in place. Both arrays - should have an equal length, and the stide of the view must be unity in all dimensions. + should have an equal length, and the view must have a contiguous memory layout. """ - function Base.$copyfun(dst::CuArray{T}, src::SubArray{T,N,A,I,true}) where {T,N,A,I} + function Base.$copyfun(dst::CuArray{T}, src::SubArray{T,N,<:DenseArray,I,true}) where {T,N,I} if length(dst) != length(src) throw(ArgumentError("Inconsistent array length.")) end - if any(strides(src) .!= 1) - throw(ArgumentError("Transfers to an array view require unit stride.")) + if any(strides(src) .!= strides(parent(src))) + throw(ArgumentError("Transfers from an array view require contiguous memory layout.")) end Mem.upload!(dst.buf, pointer(src), length(src) * sizeof(T)) return dst end + function Base.$copyfun(dst::CuArray, src::SubArray) + throw(ArgumentError("Transfers from an array view require a contiguous memory layout.")) + end + """ $copyfun{T}(dst::SubArray{T,N,A,I,true}, src::CuArray{T}) Copy an array from a device array `src` to a host array view `dst` in place. Both arrays - should have an equal length, and the stride of the view must be unity in all dimensions. + should have an equal length, and the view must have a contiguous memory layout. """ - function Base.$copyfun(dst::SubArray{T,N,A,I,true}, src::CuArray{T}) where {T,N,A,I} + function Base.$copyfun(dst::SubArray{T,N,<:DenseArray,I,true}, src::CuArray{T}) where {T,N,I} if length(dst) != length(src) throw(ArgumentError("Inconsistent array length.")) end - if any(strides(dst) .!= 1) - throw(ArgumentError("Transfers to an array view require unit stride.")) + if any(strides(dst) .!= strides(parent(dst))) + throw(ArgumentError("Transfers to an array view require contiguous memory layout.")) end Mem.download!(pointer(dst), src.buf, length(src) * sizeof(T)) return dst end + function Base.$copyfun(dst::SubArray, src::CuArray) + throw(ArgumentError("Transfers to an array view require a contiguous memory layout.")) + end + end diff --git a/test/array.jl b/test/array.jl index bcd67a7..8672978 100644 --- a/test/array.jl +++ b/test/array.jl @@ -98,6 +98,33 @@ let @assert cpu == cpu_back end + # copy views to and from device + let + gpu = CuArray{Float32}(10,10,3) + cpu = rand(Float32, 10,10,10) + + cpuv1 = view(cpu, :, :, 1:3) + + copy!(gpu, cpuv1) + + cpu_back = Array{Float32}(uninitialized, 10, 10, 3) + copy!(cpu_back, gpu) + @assert cpuv1 == cpu_back + + cpuv1 .= 0 + copy!(cpuv1, gpu) + @assert cpuv1 == cpu[:,:,1:3] + + cpuv2 = view(cpu, 1:3, :, :) # correct length, not contiguous + @test_throws ArgumentError copy!(gpu, cpuv2) + + cpuv3 = view(cpu, :, :, 1:4) # wrong dimensions, but contiguous + @test_throws ArgumentError copy!(gpu, cpuv3) + + end + + + # copy on device let gpu = CuArray(rand(Float32, 10)) gpu_copy = copy(gpu)