diff --git a/base/deprecated.jl b/base/deprecated.jl index 552d7f45d23437..ceb7378ca6a022 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -1014,14 +1014,6 @@ isempty(::Task) = error("isempty not defined for Tasks") @deprecate Array(::Type{T}, m::Integer,n::Integer) where {T} Array{T}(Int(m),Int(n)) @deprecate Array(::Type{T}, m::Integer,n::Integer,o::Integer) where {T} Array{T}(Int(m),Int(n),Int(o)) -# Likewise for SharedArrays -@deprecate SharedArray(::Type{T}, dims::Dims{N}; kwargs...) where {T,N} SharedArray{T}(dims; kwargs...) -@deprecate SharedArray(::Type{T}, dims::Int...; kwargs...) where {T} SharedArray{T}(dims...; kwargs...) -@deprecate(SharedArray(filename::AbstractString, ::Type{T}, dims::NTuple{N,Int}, offset; kwargs...) where {T,N}, - SharedArray{T}(filename, dims, offset; kwargs...)) -@deprecate(SharedArray(filename::AbstractString, ::Type{T}, dims::NTuple, offset; kwargs...) where {T}, - SharedArray{T}(filename, dims, offset; kwargs...)) - @noinline function is_intrinsic_expr(@nospecialize(x)) Base.depwarn("is_intrinsic_expr is deprecated. There are no intrinsic functions anymore.", :is_intrinsic_expr) return false @@ -1381,6 +1373,10 @@ end export Test deprecate(@__MODULE__, :Test) +@deprecate_moved SharedArray "SharedArrays" true true + +@deprecate_binding Mmap nothing true ", run `using Mmap` instead" + # PR #21709 @deprecate cov(x::AbstractVector, corrected::Bool) cov(x, corrected=corrected) @deprecate cov(x::AbstractMatrix, vardim::Int, corrected::Bool) cov(x, vardim, corrected=corrected) diff --git a/base/exports.jl b/base/exports.jl index 62680eda16b597..09fd49d701fb25 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -11,7 +11,6 @@ export Sys, Libc, Libdl, - Mmap, LinAlg, BLAS, LAPACK, @@ -104,9 +103,6 @@ export AbstractSerializer, SerializationState, Set, - SharedArray, - SharedMatrix, - SharedVector, StepRange, StepRangeLen, StridedArray, @@ -1088,11 +1084,6 @@ export HTML, Text, -# shared arrays - sdata, - indexpids, - localindexes, - # paths and file names abspath, basename, diff --git a/base/sysimg.jl b/base/sysimg.jl index 7609ab098fad2e..93ae630bd40345 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -355,10 +355,6 @@ using .Serializer import .Serializer: serialize, deserialize include("channels.jl") -# memory-mapped and shared arrays -include("mmap.jl") -import .Mmap - # utilities - timing, help, edit include("deepcopy.jl") include("interactiveutil.jl") @@ -413,7 +409,6 @@ include("asyncmap.jl") include("distributed/Distributed.jl") using .Distributed -include("sharedarray.jl") # code loading include("loading.jl") diff --git a/doc/make.jl b/doc/make.jl index 2ba1dfd9a72019..0477cc7cc35075 100644 --- a/doc/make.jl +++ b/doc/make.jl @@ -16,13 +16,20 @@ end # Documenter Setup. +symlink_q(tgt, link) = isfile(link) || symlink(tgt, link) +cp_q(src, dest) = isfile(dest) || cp(src, dest) + # make links for stdlib package docs if Sys.iswindows() - cp("../stdlib/DelimitedFiles/docs/src/index.md", "src/stdlib/delimitedfiles.md") - cp("../stdlib/Test/docs/src/index.md", "src/stdlib/test.md") + cp_q("../stdlib/DelimitedFiles/docs/src/index.md", "src/stdlib/delimitedfiles.md") + cp_q("../stdlib/Test/docs/src/index.md", "src/stdlib/test.md") + cp_q("../stdlib/Mmap/docs/src/index.md", "src/stdlib/mmap.md") + cp_q("../stdlib/SharedArrays/docs/src/index.md", "src/stdlib/sharedarrays.md") else - symlink("../../../stdlib/DelimitedFiles/docs/src/index.md", "src/stdlib/delimitedfiles.md") - symlink("../../../stdlib/Test/docs/src/index.md", "src/stdlib/test.md") + symlink_q("../../../stdlib/DelimitedFiles/docs/src/index.md", "src/stdlib/delimitedfiles.md") + symlink_q("../../../stdlib/Test/docs/src/index.md", "src/stdlib/test.md") + symlink_q("../../../stdlib/Mmap/docs/src/index.md", "src/stdlib/mmap.md") + symlink_q("../../../stdlib/SharedArrays/docs/src/index.md", "src/stdlib/sharedarrays.md") end const PAGES = [ @@ -126,11 +133,11 @@ const PAGES = [ ], ] -using DelimitedFiles, Test +using DelimitedFiles, Test, Mmap, SharedArrays makedocs( build = joinpath(pwd(), "_build/html/en"), - modules = [Base, Core, BuildSysImg, DelimitedFiles, Test], + modules = [Base, Core, BuildSysImg, DelimitedFiles, Test, Mmap, SharedArrays], clean = false, doctest = "doctest" in ARGS, linkcheck = "linkcheck" in ARGS, diff --git a/doc/src/manual/parallel-computing.md b/doc/src/manual/parallel-computing.md index 90e8c0b465b91e..2d720d6b3c7def 100644 --- a/doc/src/manual/parallel-computing.md +++ b/doc/src/manual/parallel-computing.md @@ -858,7 +858,9 @@ julia> addprocs(3) 3 4 -julia> S = SharedArray{Int,2}((3,4), init = S -> S[Base.localindexes(S)] = myid()) +julia> @everywhere using SharedArrays + +julia> S = SharedArray{Int,2}((3,4), init = S -> S[localindexes(S)] = myid()) 3×4 SharedArray{Int64,2}: 2 2 3 4 2 3 3 4 @@ -874,7 +876,7 @@ julia> S 2 7 4 4 ``` -[`Base.localindexes`](@ref) provides disjoint one-dimensional ranges of indexes, and is sometimes +[`SharedArrays.localindexes`](@ref) provides disjoint one-dimensional ranges of indexes, and is sometimes convenient for splitting up tasks among processes. You can, of course, divide the work any way you wish: diff --git a/doc/src/stdlib/.gitignore b/doc/src/stdlib/.gitignore index 39d3308169806e..fbc2433331fa7a 100644 --- a/doc/src/stdlib/.gitignore +++ b/doc/src/stdlib/.gitignore @@ -1,2 +1,4 @@ delimitedfiles.md test.md +mmap.md +sharedarrays.md diff --git a/doc/src/stdlib/index.md b/doc/src/stdlib/index.md index 05346024aff828..4fcb10d71e77d1 100644 --- a/doc/src/stdlib/index.md +++ b/doc/src/stdlib/index.md @@ -24,3 +24,5 @@ * [Dynamic Linker](@ref) * [Profiling](@ref lib-profiling) * [SIMD Support](@ref) + * [Memory-mapped I/O](@ref) + * [Shared Arrays](@ref) diff --git a/doc/src/stdlib/io-network.md b/doc/src/stdlib/io-network.md index 91ad6151eb2470..482ceb3d7015cd 100644 --- a/doc/src/stdlib/io-network.md +++ b/doc/src/stdlib/io-network.md @@ -136,14 +136,6 @@ Base.Multimedia.TextDisplay Base.Multimedia.istextmime ``` -## Memory-mapped I/O - -```@docs -Base.Mmap.Anonymous -Base.Mmap.mmap -Base.Mmap.sync! -``` - ## Network I/O ```@docs diff --git a/doc/src/stdlib/parallel.md b/doc/src/stdlib/parallel.md index 17f19ec64ab3c4..3706eb2c8c7568 100644 --- a/doc/src/stdlib/parallel.md +++ b/doc/src/stdlib/parallel.md @@ -83,16 +83,6 @@ Base.cluster_cookie() Base.cluster_cookie(::Any) ``` -## Shared Arrays - -```@docs -Base.SharedArray -Base.procs(::SharedArray) -Base.sdata -Base.indexpids -Base.localindexes -``` - ## Multi-Threading This experimental interface supports Julia's multi-threading capabilities. Types and functions diff --git a/stdlib/DelimitedFiles/src/DelimitedFiles.jl b/stdlib/DelimitedFiles/src/DelimitedFiles.jl index 4377288166e673..48fe7a95846574 100644 --- a/stdlib/DelimitedFiles/src/DelimitedFiles.jl +++ b/stdlib/DelimitedFiles/src/DelimitedFiles.jl @@ -4,6 +4,8 @@ __precompile__(true) module DelimitedFiles +using Mmap + import Base: _default_delims, tryparse_internal, show export readdlm, writedlm diff --git a/stdlib/Mmap/docs/src/index.md b/stdlib/Mmap/docs/src/index.md new file mode 100644 index 00000000000000..ada88b153de645 --- /dev/null +++ b/stdlib/Mmap/docs/src/index.md @@ -0,0 +1,7 @@ +# Memory-mapped I/O + +```@docs +Mmap.Anonymous +Mmap.mmap +Mmap.sync! +``` diff --git a/base/mmap.jl b/stdlib/Mmap/src/Mmap.jl similarity index 100% rename from base/mmap.jl rename to stdlib/Mmap/src/Mmap.jl diff --git a/test/mmap.jl b/stdlib/Mmap/test/runtests.jl similarity index 99% rename from test/mmap.jl rename to stdlib/Mmap/test/runtests.jl index 3e62acf5187d31..e68d1fda000c7b 100644 --- a/test/mmap.jl +++ b/stdlib/Mmap/test/runtests.jl @@ -1,5 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +using Test, Mmap + file = tempname() write(file, "Hello World\n") t = b"Hello World" diff --git a/stdlib/SharedArrays/docs/src/index.md b/stdlib/SharedArrays/docs/src/index.md new file mode 100644 index 00000000000000..25e54030bd5e3a --- /dev/null +++ b/stdlib/SharedArrays/docs/src/index.md @@ -0,0 +1,9 @@ +# Shared Arrays + +```@docs +SharedArrays.SharedArray +SharedArrays.procs(::SharedArray) +SharedArrays.sdata +SharedArrays.indexpids +SharedArrays.localindexes +``` diff --git a/base/sharedarray.jl b/stdlib/SharedArrays/src/SharedArrays.jl similarity index 94% rename from base/sharedarray.jl rename to stdlib/SharedArrays/src/SharedArrays.jl index d1c5070f02f0cf..9d38aa2bfb864e 100644 --- a/base/sharedarray.jl +++ b/stdlib/SharedArrays/src/SharedArrays.jl @@ -1,7 +1,17 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -import .Serializer: serialize_cycle_header, serialize_type, writetag, UNDEFREF_TAG -import .Distributed: RRID, procs +module SharedArrays + +using Mmap, Base.Distributed + +import Base: length, size, ndims, IndexStyle, reshape, convert, deepcopy_internal, serialize, deserialize, + show, getindex, setindex!, fill!, rand!, similar, reduce, map!, copy!, unsafe_convert +import Base.Random +import Base.Serializer: serialize_cycle_header, serialize_type, writetag, UNDEFREF_TAG +import Base.Distributed: RRID, procs +import Base.Filesystem: JL_O_CREAT, JL_O_RDWR, S_IRUSR, S_IWUSR + +export SharedArray, SharedVector, SharedMatrix, sdata, indexpids, localindexes mutable struct SharedArray{T,N} <: DenseArray{T,N} id::RRID @@ -663,6 +673,17 @@ end shm_unlink(shm_seg_name) = ccall(:shm_unlink, Cint, (Cstring,), shm_seg_name) shm_open(shm_seg_name, oflags, permissions) = ccall(:shm_open, Cint, - (Cstring, Cint, Cmode_t), shm_seg_name, oflags, permissions) + (Cstring, Cint, Base.Cmode_t), shm_seg_name, oflags, permissions) end # os-test + +# 0.7 deprecations + +@deprecate SharedArray(::Type{T}, dims::Dims{N}; kwargs...) where {T,N} SharedArray{T}(dims; kwargs...) +@deprecate SharedArray(::Type{T}, dims::Int...; kwargs...) where {T} SharedArray{T}(dims...; kwargs...) +@deprecate(SharedArray(filename::AbstractString, ::Type{T}, dims::NTuple{N,Int}, offset; kwargs...) where {T,N}, + SharedArray{T}(filename, dims, offset; kwargs...)) +@deprecate(SharedArray(filename::AbstractString, ::Type{T}, dims::NTuple, offset; kwargs...) where {T}, + SharedArray{T}(filename, dims, offset; kwargs...)) + +end # module diff --git a/stdlib/SharedArrays/test/runtests.jl b/stdlib/SharedArrays/test/runtests.jl new file mode 100644 index 00000000000000..f163d60f65f01a --- /dev/null +++ b/stdlib/SharedArrays/test/runtests.jl @@ -0,0 +1,306 @@ +using Test, SharedArrays +include("../../../test/testenv.jl") + +# Test a few "remote" invocations when no workers are present +@test remote(myid)() == 1 +@test pmap(identity, 1:100) == [1:100...] +@test 100 == @parallel (+) for i in 1:100 + 1 + end + +addprocs_with_testenv(4) +@test nprocs() == 5 + +@everywhere using Test, SharedArrays + +id_me = myid() +id_other = filter(x -> x != id_me, procs())[rand(1:(nprocs()-1))] + +dims = (20,20,20) + +if Sys.islinux() + S = SharedArray{Int64,3}(dims) + @test startswith(S.segname, "/jl") + @test !ispath("/dev/shm" * S.segname) + + S = SharedArray{Int64,3}(dims; pids=[id_other]) + @test startswith(S.segname, "/jl") + @test !ispath("/dev/shm" * S.segname) +end + +# TODO : Need a similar test of shmem cleanup for OSX + +##### SharedArray tests + +function check_pids_all(S::SharedArray) + pidtested = falses(size(S)) + for p in procs(S) + idxes_in_p = remotecall_fetch(p, S) do D + parentindexes(D.loc_subarr_1d)[1] + end + @test all(sdata(S)[idxes_in_p] .== p) + pidtested[idxes_in_p] = true + end + @test all(pidtested) +end + +d = SharedArrays.shmem_rand(1:100, dims) +a = convert(Array, d) + +partsums = Array{Int}(length(procs(d))) +@sync begin + for (i, p) in enumerate(procs(d)) + @async partsums[i] = remotecall_fetch(p, d) do D + sum(D.loc_subarr_1d) + end + end +end +@test sum(a) == sum(partsums) + +d = SharedArrays.shmem_rand(dims) +for p in procs(d) + idxes_in_p = remotecall_fetch(p, d) do D + parentindexes(D.loc_subarr_1d)[1] + end + idxf = first(idxes_in_p) + idxl = last(idxes_in_p) + d[idxf] = Float64(idxf) + rv = remotecall_fetch(p, d,idxf,idxl) do D,idxf,idxl + assert(D[idxf] == Float64(idxf)) + D[idxl] = Float64(idxl) + D[idxl] + end + @test d[idxl] == rv +end + +@test ones(10, 10, 10) == SharedArrays.shmem_fill(1.0, (10,10,10)) +@test zeros(Int32, 10, 10, 10) == SharedArrays.shmem_fill(0, (10,10,10)) + +d = SharedArrays.shmem_rand(dims) +s = SharedArrays.shmem_rand(dims) +copy!(s, d) +@test s == d +s = SharedArrays.shmem_rand(dims) +copy!(s, sdata(d)) +@test s == d +a = rand(dims) +@test sdata(a) == a + +d = SharedArray{Int}(dims, init = D->fill!(D.loc_subarr_1d, myid())) +for p in procs(d) + idxes_in_p = remotecall_fetch(p, d) do D + parentindexes(D.loc_subarr_1d)[1] + end + idxf = first(idxes_in_p) + idxl = last(idxes_in_p) + @test d[idxf] == p + @test d[idxl] == p +end + +d = @inferred(SharedArray{Float64,2}((2,3))) +@test isa(d[:,2], Vector{Float64}) + +### SharedArrays from a file + +# Mapping an existing file +fn = tempname() +write(fn, 1:30) +sz = (6,5) +Atrue = reshape(1:30, sz) + +S = @inferred(SharedArray{Int,2}(fn, sz)) +@test S == Atrue +@test length(procs(S)) > 1 +@everywhere procs(S) begin + $fill!($S.loc_subarr_1d, $myid()) +end +check_pids_all(S) + +filedata = similar(Atrue) +read!(fn, filedata) +@test filedata == sdata(S) +finalize(S) + +# Error for write-only files +@test_throws ArgumentError SharedArray{Int,2}(fn, sz, mode="w") + +# Error for file doesn't exist, but not allowed to create +@test_throws ArgumentError SharedArray{Int,2}(joinpath(tempdir(),randstring()), sz, mode="r") + +# Creating a new file +fn2 = tempname() +S = SharedArray{Int,2}(fn2, sz, init=D->D[localindexes(D)] = myid()) +@test S == filedata +filedata2 = similar(Atrue) +read!(fn2, filedata2) +@test filedata == filedata2 +finalize(S) + +# Appending to a file +fn3 = tempname() +write(fn3, ones(UInt8, 4)) +S = SharedArray{UInt8}(fn3, sz, 4, mode="a+", init=D->D[localindexes(D)]=0x02) +len = prod(sz)+4 +@test filesize(fn3) == len +filedata = Array{UInt8}(len) +read!(fn3, filedata) +@test all(filedata[1:4] .== 0x01) +@test all(filedata[5:end] .== 0x02) +finalize(S) + +# call gc 3 times to avoid unlink: operation not permitted (EPERM) on Windows +S = nothing +@everywhere gc() +@everywhere gc() +@everywhere gc() +rm(fn); rm(fn2); rm(fn3) + +### Utility functions + +# construct PR #13514 +S = @inferred(SharedArray{Int}((1,2,3))) +@test size(S) == (1,2,3) +@test typeof(S) <: SharedArray{Int} +S = @inferred(SharedArray{Int}(2)) +@test size(S) == (2,) +@test typeof(S) <: SharedArray{Int} +S = @inferred(SharedArray{Int}(1,2)) +@test size(S) == (1,2) +@test typeof(S) <: SharedArray{Int} +S = @inferred(SharedArray{Int}(1,2,3)) +@test size(S) == (1,2,3) +@test typeof(S) <: SharedArray{Int} + +# reshape + +d = SharedArrays.shmem_fill(1.0, (10,10,10)) +@test ones(100, 10) == reshape(d,(100,10)) +d = SharedArrays.shmem_fill(1.0, (10,10,10)) +@test_throws DimensionMismatch reshape(d,(50,)) + +# rand, randn +d = SharedArrays.shmem_rand(dims) +@test size(rand!(d)) == dims +d = SharedArrays.shmem_fill(1.0, dims) +@test size(randn!(d)) == dims + +# similar +d = SharedArrays.shmem_rand(dims) +@test size(similar(d, Complex128)) == dims +@test size(similar(d, dims)) == dims + +# issue #6362 +d = SharedArrays.shmem_rand(dims) +s = copy(sdata(d)) +ds = deepcopy(d) +@test ds == d +pids_d = procs(d) +remotecall_fetch(setindex!, pids_d[findfirst(id->(id != myid()), pids_d)], d, 1.0, 1:10) +@test ds != d +@test s != d +copy!(d, s) +@everywhere setid!(A) = A[localindexes(A)] = myid() +@everywhere procs(ds) setid!($ds) +@test d == s +@test ds != s +@test first(ds) == first(procs(ds)) +@test last(ds) == last(procs(ds)) + + +# SharedArray as an array +# Since the data in d will depend on the nprocs, just test that these operations work +a = d[1:5] +@test_throws BoundsError d[-1:5] +a = d[1,1,1:3:end] +d[2:4] = 7 +d[5,1:2:4,8] = 19 + +AA = rand(4,2) +A = @inferred(convert(SharedArray, AA)) +B = @inferred(convert(SharedArray, AA')) +@test B*A == adjoint(AA)*AA + +d=SharedArray{Int64,2}((10,10); init = D->fill!(D.loc_subarr_1d, myid()), pids=[id_me, id_other]) +d2 = map(x->1, d) +@test reduce(+, d2) == 100 + +@test reduce(+, d) == ((50*id_me) + (50*id_other)) +map!(x->1, d, d) +@test reduce(+, d) == 100 + +@test fill!(d, 1) == ones(10, 10) +@test fill!(d, 2.) == fill(2, 10, 10) +@test d[:] == fill(2, 100) +@test d[:,1] == fill(2, 10) +@test d[1,:] == fill(2, 10) + +# Boundary cases where length(S) <= length(pids) +@test 2.0 == remotecall_fetch(D->D[2], id_other, SharedArrays.shmem_fill(2.0, 2; pids=[id_me, id_other])) +@test 3.0 == remotecall_fetch(D->D[1], id_other, SharedArrays.shmem_fill(3.0, 1; pids=[id_me, id_other])) + +# Shared arrays of singleton immutables +@everywhere struct ShmemFoo end +for T in [Void, ShmemFoo] + local s = @inferred(SharedArray{T}(10)) + @test T() === remotecall_fetch(x->x[3], workers()[1], s) +end + +# Issue #14664 +d = SharedArray{Int}(10) +@sync @parallel for i=1:10 + d[i] = i +end + +for (x,i) in enumerate(d) + @test x == i +end + +# complex +sd = SharedArray{Int}(10) +se = SharedArray{Int}(10) +@sync @parallel for i=1:10 + sd[i] = i + se[i] = i +end +sc = convert(SharedArray, complex.(sd,se)) +for (x,i) in enumerate(sc) + @test i == complex(x,x) +end + +# Once finalized accessing remote references and shared arrays should result in exceptions. +function finalize_and_test(r) + finalize(r) + @test_throws ErrorException fetch(r) +end + +for id in [id_me, id_other] + local id + finalize_and_test(Future(id)) + finalize_and_test((r=Future(id); put!(r, 1); r)) + finalize_and_test(RemoteChannel(id)) + finalize_and_test((r=RemoteChannel(id); put!(r, 1); r)) +end + +d = SharedArray{Int}(10) +finalize(d) +@test_throws BoundsError d[1] + +# Issue 22139 +let + aorig = a1 = SharedArray{Float64}((3, 3)) + a1 = remotecall_fetch(fill!, id_other, a1, 1.0) + @test object_id(aorig) == object_id(a1) + id = a1.id + aorig = nothing + a1 = remotecall_fetch(fill!, id_other, a1, 1.0) + gc(); gc() + a1 = remotecall_fetch(fill!, id_other, a1, 1.0) + @test haskey(SharedArrays.sa_refs, id) + finalize(a1) + @test !haskey(SharedArrays.sa_refs, id) +end + +#14399 +let s = convert(SharedArray, [1,2,3,4]) + @test pmap(i->length(s), 1:2) == [4,4] +end diff --git a/test/choosetests.jl b/test/choosetests.jl index c769fe9d44dca2..2d82a08631d0d7 100644 --- a/test/choosetests.jl +++ b/test/choosetests.jl @@ -30,7 +30,7 @@ function choosetests(choices = []) "bitarray", "copy", "math", "fastmath", "functional", "iterators", "operators", "path", "ccall", "parse", "loading", "bigint", "bigfloat", "sorting", "statistics", "spawn", "backtrace", - "file", "read", "mmap", "version", "resolve", + "file", "read", "version", "resolve", "pollfd", "mpfr", "broadcast", "complex", "socket", "floatapprox", "stdlib", "reflection", "regex", "float16", "combinatorics", "sysinfo", "env", "rounding", "ranges", "mod2pi", diff --git a/test/distributed_exec.jl b/test/distributed_exec.jl index 4f4d6ab2d960be..aef236880a3f07 100644 --- a/test/distributed_exec.jl +++ b/test/distributed_exec.jl @@ -269,290 +269,6 @@ end test_regular_io_ser(Future()) test_regular_io_ser(RemoteChannel()) -dims = (20,20,20) - -if Sys.islinux() - S = SharedArray{Int64,3}(dims) - @test startswith(S.segname, "/jl") - @test !ispath("/dev/shm" * S.segname) - - S = SharedArray{Int64,3}(dims; pids=[id_other]) - @test startswith(S.segname, "/jl") - @test !ispath("/dev/shm" * S.segname) -end - -# TODO : Need a similar test of shmem cleanup for OSX - -##### SharedArray tests - -function check_pids_all(S::SharedArray) - pidtested = falses(size(S)) - for p in procs(S) - idxes_in_p = remotecall_fetch(p, S) do D - parentindexes(D.loc_subarr_1d)[1] - end - @test all(sdata(S)[idxes_in_p] .== p) - pidtested[idxes_in_p] = true - end - @test all(pidtested) -end - -d = Base.shmem_rand(1:100, dims) -a = convert(Array, d) - -partsums = Array{Int}(length(procs(d))) -@sync begin - for (i, p) in enumerate(procs(d)) - @async partsums[i] = remotecall_fetch(p, d) do D - sum(D.loc_subarr_1d) - end - end -end -@test sum(a) == sum(partsums) - -d = Base.shmem_rand(dims) -for p in procs(d) - idxes_in_p = remotecall_fetch(p, d) do D - parentindexes(D.loc_subarr_1d)[1] - end - idxf = first(idxes_in_p) - idxl = last(idxes_in_p) - d[idxf] = Float64(idxf) - rv = remotecall_fetch(p, d,idxf,idxl) do D,idxf,idxl - assert(D[idxf] == Float64(idxf)) - D[idxl] = Float64(idxl) - D[idxl] - end - @test d[idxl] == rv -end - -@test ones(10, 10, 10) == Base.shmem_fill(1.0, (10,10,10)) -@test zeros(Int32, 10, 10, 10) == Base.shmem_fill(0, (10,10,10)) - -d = Base.shmem_rand(dims) -s = Base.shmem_rand(dims) -copy!(s, d) -@test s == d -s = Base.shmem_rand(dims) -copy!(s, sdata(d)) -@test s == d -a = rand(dims) -@test sdata(a) == a - -d = SharedArray{Int}(dims, init = D->fill!(D.loc_subarr_1d, myid())) -for p in procs(d) - idxes_in_p = remotecall_fetch(p, d) do D - parentindexes(D.loc_subarr_1d)[1] - end - idxf = first(idxes_in_p) - idxl = last(idxes_in_p) - @test d[idxf] == p - @test d[idxl] == p -end - -d = @inferred(SharedArray{Float64,2}((2,3))) -@test isa(d[:,2], Vector{Float64}) - -### SharedArrays from a file - -# Mapping an existing file -fn = tempname() -write(fn, 1:30) -sz = (6,5) -Atrue = reshape(1:30, sz) - -S = @inferred(SharedArray{Int,2}(fn, sz)) -@test S == Atrue -@test length(procs(S)) > 1 -@everywhere procs(S) begin - $fill!($S.loc_subarr_1d, $myid()) -end -check_pids_all(S) - -filedata = similar(Atrue) -read!(fn, filedata) -@test filedata == sdata(S) -finalize(S) - -# Error for write-only files -@test_throws ArgumentError SharedArray{Int,2}(fn, sz, mode="w") - -# Error for file doesn't exist, but not allowed to create -@test_throws ArgumentError SharedArray{Int,2}(joinpath(tempdir(),randstring()), sz, mode="r") - -# Creating a new file -fn2 = tempname() -S = SharedArray{Int,2}(fn2, sz, init=D->D[localindexes(D)] = myid()) -@test S == filedata -filedata2 = similar(Atrue) -read!(fn2, filedata2) -@test filedata == filedata2 -finalize(S) - -# Appending to a file -fn3 = tempname() -write(fn3, ones(UInt8, 4)) -S = SharedArray{UInt8}(fn3, sz, 4, mode="a+", init=D->D[localindexes(D)]=0x02) -len = prod(sz)+4 -@test filesize(fn3) == len -filedata = Array{UInt8}(len) -read!(fn3, filedata) -@test all(filedata[1:4] .== 0x01) -@test all(filedata[5:end] .== 0x02) -finalize(S) - -# call gc 3 times to avoid unlink: operation not permitted (EPERM) on Windows -S = nothing -@everywhere gc() -@everywhere gc() -@everywhere gc() -rm(fn); rm(fn2); rm(fn3) - -### Utility functions - -# construct PR #13514 -S = @inferred(SharedArray{Int}((1,2,3))) -@test size(S) == (1,2,3) -@test typeof(S) <: SharedArray{Int} -S = @inferred(SharedArray{Int}(2)) -@test size(S) == (2,) -@test typeof(S) <: SharedArray{Int} -S = @inferred(SharedArray{Int}(1,2)) -@test size(S) == (1,2) -@test typeof(S) <: SharedArray{Int} -S = @inferred(SharedArray{Int}(1,2,3)) -@test size(S) == (1,2,3) -@test typeof(S) <: SharedArray{Int} - -# reshape - -d = Base.shmem_fill(1.0, (10,10,10)) -@test ones(100, 10) == reshape(d,(100,10)) -d = Base.shmem_fill(1.0, (10,10,10)) -@test_throws DimensionMismatch reshape(d,(50,)) - -# rand, randn -d = Base.shmem_rand(dims) -@test size(rand!(d)) == dims -d = Base.shmem_fill(1.0, dims) -@test size(randn!(d)) == dims - -# similar -d = Base.shmem_rand(dims) -@test size(similar(d, Complex128)) == dims -@test size(similar(d, dims)) == dims - -# issue #6362 -d = Base.shmem_rand(dims) -s = copy(sdata(d)) -ds = deepcopy(d) -@test ds == d -pids_d = procs(d) -remotecall_fetch(setindex!, pids_d[findfirst(id->(id != myid()), pids_d)], d, 1.0, 1:10) -@test ds != d -@test s != d -copy!(d, s) -@everywhere setid!(A) = A[localindexes(A)] = myid() -@everywhere procs(ds) setid!($ds) -@test d == s -@test ds != s -@test first(ds) == first(procs(ds)) -@test last(ds) == last(procs(ds)) - - -# SharedArray as an array -# Since the data in d will depend on the nprocs, just test that these operations work -a = d[1:5] -@test_throws BoundsError d[-1:5] -a = d[1,1,1:3:end] -d[2:4] = 7 -d[5,1:2:4,8] = 19 - -AA = rand(4,2) -A = @inferred(convert(SharedArray, AA)) -B = @inferred(convert(SharedArray, AA')) -@test B*A == adjoint(AA)*AA - -d=SharedArray{Int64,2}((10,10); init = D->fill!(D.loc_subarr_1d, myid()), pids=[id_me, id_other]) -d2 = map(x->1, d) -@test reduce(+, d2) == 100 - -@test reduce(+, d) == ((50*id_me) + (50*id_other)) -map!(x->1, d, d) -@test reduce(+, d) == 100 - -@test fill!(d, 1) == ones(10, 10) -@test fill!(d, 2.) == fill(2, 10, 10) -@test d[:] == fill(2, 100) -@test d[:,1] == fill(2, 10) -@test d[1,:] == fill(2, 10) - -# Boundary cases where length(S) <= length(pids) -@test 2.0 == remotecall_fetch(D->D[2], id_other, Base.shmem_fill(2.0, 2; pids=[id_me, id_other])) -@test 3.0 == remotecall_fetch(D->D[1], id_other, Base.shmem_fill(3.0, 1; pids=[id_me, id_other])) - -# Shared arrays of singleton immutables -@everywhere struct ShmemFoo end -for T in [Void, ShmemFoo] - local s = @inferred(SharedArray{T}(10)) - @test T() === remotecall_fetch(x->x[3], workers()[1], s) -end - -# Issue #14664 -d = SharedArray{Int}(10) -@sync @parallel for i=1:10 - d[i] = i -end - -for (x,i) in enumerate(d) - @test x == i -end - -# complex -sd = SharedArray{Int}(10) -se = SharedArray{Int}(10) -@sync @parallel for i=1:10 - sd[i] = i - se[i] = i -end -sc = convert(SharedArray, complex.(sd,se)) -for (x,i) in enumerate(sc) - @test i == complex(x,x) -end - -# Once finalized accessing remote references and shared arrays should result in exceptions. -function finalize_and_test(r) - finalize(r) - @test_throws ErrorException fetch(r) -end - -for id in [id_me, id_other] - local id - finalize_and_test(Future(id)) - finalize_and_test((r=Future(id); put!(r, 1); r)) - finalize_and_test(RemoteChannel(id)) - finalize_and_test((r=RemoteChannel(id); put!(r, 1); r)) -end - -d = SharedArray{Int}(10) -finalize(d) -@test_throws BoundsError d[1] - -# Issue 22139 -let - aorig = a1 = SharedArray{Float64}((3, 3)) - a1 = remotecall_fetch(fill!, id_other, a1, 1.0) - @test object_id(aorig) == object_id(a1) - id = a1.id - aorig = nothing - a1 = remotecall_fetch(fill!, id_other, a1, 1.0) - gc(); gc() - a1 = remotecall_fetch(fill!, id_other, a1, 1.0) - @test haskey(Base.sa_refs, id) - finalize(a1) - @test !haskey(Base.sa_refs, id) -end - # Test @parallel load balancing - all processors should get either M or M+1 # iterations out of the loop range for some M. ids = @parallel((a,b)->[a;b], for i=1:7; myid(); end) @@ -1614,10 +1330,6 @@ if true end foreach(wait, refs) -#14399 -s = convert(SharedArray, [1,2,3,4]) -@test pmap(i->length(s), 1:2) == [4,4] - #6760 if true a = 2