Skip to content

Commit 796d1ea

Browse files
Merge pull request #17 from brenhinkeller/withmallocarray
Support "withmallocarray"-type do-block syntax for most `MallocArray` constructors
2 parents 3c236e4 + b42c65a commit 796d1ea

File tree

4 files changed

+194
-19
lines changed

4 files changed

+194
-19
lines changed

src/mallocarray.jl

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@
3838

3939
"""
4040
```julia
41+
MallocArray(T, dims) do A
42+
...
43+
end
44+
```
45+
```julia
4146
MallocArray{T}(undef, dims)
4247
MallocArray{T,N}(undef, dims)
4348
```
@@ -82,6 +87,17 @@
8287
julia> free(A)
8388
0
8489
```
90+
To avoid having to manually `free` allocated memory, it is recommended to
91+
use the following supported do-block syntax whenever possible, i.e.
92+
```julia
93+
julia> MallocArray(Float64, 2, 2) do A
94+
A .= 0
95+
printf(A)
96+
end
97+
0.000000e+00 0.000000e+00
98+
0.000000e+00 0.000000e+00
99+
0
100+
```
85101
"""
86102
@inline function MallocArray{T,N}(::UndefInitializer, length::Int, dims::Dims{N}) where {T,N}
87103
@assert Base.allocatedinline(T)
@@ -99,6 +115,12 @@
99115
@inline MallocArray{T}(x::PointerOrInitializer, dims::Dims{N}) where {T,N} = MallocArray{T,N}(x, prod(dims), dims)
100116
@inline MallocArray{T,N}(x::PointerOrInitializer, dims::Vararg{Int}) where {T,N} = MallocArray{T,N}(x, prod(dims), dims)
101117
@inline MallocArray{T}(x::PointerOrInitializer, dims::Vararg{Int}) where {T} = MallocArray{T}(x, dims)
118+
@inline function MallocArray(f::Function, T::Type, dims...)
119+
M = MallocArray{T}(undef, dims...)
120+
y = f(M)
121+
free(M)
122+
y
123+
end
102124

103125
"""
104126
```julia
@@ -127,6 +149,7 @@
127149
"""
128150
@inline MallocArray(x::AbstractArray{T,N}) where {T,N} = copyto!(MallocArray{T,N}(undef, length(x), size(x)), x)
129151

152+
130153
# Destructor:
131154
@inline free(a::MallocArray) = free(a.pointer)
132155

@@ -145,6 +168,11 @@
145168
# Other custom constructors
146169
"""
147170
```julia
171+
mzeros([T], dims) do A
172+
...
173+
end
174+
```
175+
```julia
148176
mzeros([T=Float64,] dims::Tuple)
149177
mzeros([T=Float64,] dims...)
150178
```
@@ -160,14 +188,35 @@
160188
0 0
161189
0 0
162190
```
191+
To avoid having to manually `free` allocated memory, it is recommended to
192+
use the following supported do-block syntax whenever possible, i.e.
193+
```julia
194+
julia> mzeros(2,2) do A
195+
printf(A)
196+
end
197+
0.000000e+00 0.000000e+00
198+
0.000000e+00 0.000000e+00
199+
0
200+
```
163201
"""
164202
@inline mzeros(dims::Vararg{Int}) = mzeros(dims)
165203
@inline mzeros(dims::Dims{N}) where {N} = MallocArray{Float64,N}(zeros, dims)
166204
@inline mzeros(T::Type, dims::Vararg{Int}) = mzeros(T, dims)
167205
@inline mzeros(::Type{T}, dims::Dims{N}) where {T,N} = MallocArray{T,N}(zeros, dims)
206+
@inline function mzeros(f::Function, args...)
207+
M = mzeros(args...)
208+
y = f(M)
209+
free(M)
210+
y
211+
end
168212

169213
"""
170214
```julia
215+
mones([T=Float64,] dims) do A
216+
...
217+
end
218+
```
219+
```julia
171220
mones([T=Float64,] dims::Tuple)
172221
mones([T=Float64,] dims...)
173222
```
@@ -178,28 +227,66 @@
178227
179228
## Examples
180229
```julia
181-
julia> mones(Int32, 2,2)
230+
julia> A = mones(Int32, 2,2)
182231
2×2 MallocMatrix{Int32}:
183232
1 1
184233
1 1
234+
235+
julia> free(A)
236+
0
237+
```
238+
To avoid having to manually `free` allocated memory, it is recommended to
239+
use the following supported do-block syntax whenever possible, i.e.
240+
```julia
241+
julia> mones(2,2) do A
242+
printf(A)
243+
end
244+
1.000000e+00 1.000000e+00
245+
1.000000e+00 1.000000e+00
246+
0
185247
```
186248
"""
187249
@inline mones(dims...) = mones(Float64, dims...)
188250
@inline mones(::Type{T}, dims...) where {T} = mfill(one(T), dims...)
251+
@inline function mones(f::Function, args...)
252+
M = mones(args...)
253+
y = f(M)
254+
free(M)
255+
y
256+
end
189257

190258
"""
191259
```julia
260+
meye([T=Float64,] dims) do A
261+
...
262+
end
263+
```
264+
```julia
192265
meye([T=Float64,] dim::Int)
193266
```
194267
Create a `MallocArray{T}` containing an identity matrix of type `T`,
195268
of size `dim` x `dim`.
196269
197270
## Examples
198271
```julia
199-
julia> meye(Int32, 2)
272+
julia> A = meye(Int32, 2)
273+
200274
2×2 MallocMatrix{Int32}:
201275
1 0
202276
0 1
277+
278+
julia> free(A)
279+
0
280+
```
281+
To avoid having to manually `free` allocated memory, it is recommended to
282+
use the following supported do-block syntax whenever possible, i.e.
283+
```julia
284+
julia> meye(2) do A
285+
printf(A)
286+
end
287+
1.000000e+00 0.000000e+00
288+
0.000000e+00 1.000000e+00
289+
0
203290
```
204291
"""
205292
@inline meye(dim::Int) = meye(Float64, dim)
@@ -211,6 +298,13 @@
211298
end
212299
return A
213300
end
301+
@inline function meye(f::Function, args...)
302+
M = meye(args...)
303+
y = f(M)
304+
free(M)
305+
y
306+
end
307+
214308

215309
"""
216310
```julia
@@ -229,9 +323,25 @@
229323
3 3
230324
3 3
231325
```
326+
To avoid having to manually `free` allocated memory, it is recommended to
327+
use the following supported do-block syntax whenever possible, i.e.
328+
```julia
329+
julia> mfill(1.5, 2,2) do A
330+
printf(A)
331+
end
332+
1.500000e+00 1.500000e+00
333+
1.500000e+00 1.500000e+00
334+
0
335+
```
232336
"""
233337
@inline mfill(x, dims::Vararg{Int}) = mfill(x, dims)
234338
@inline function mfill(x::T, dims::Dims{N}) where {T,N}
235339
A = MallocArray{T,N}(undef, prod(dims), dims)
236340
fill!(A, x)
237341
end
342+
@inline function mfill(f::Function, args...)
343+
M = mfill(args...)
344+
y = f(M)
345+
free(M)
346+
y
347+
end

test/scripts/withmallocarray.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using StaticCompiler
2+
using StaticTools
3+
4+
function withmallocarray(argc::Int, argv::Ptr{Ptr{UInt8}})
5+
argc == 3 || return printf(stderrp(), c"Incorrect number of command-line arguments\n")
6+
rows = parse(Int64, argv, 2) # First command-line argument
7+
cols = parse(Int64, argv, 3) # Second command-line argument
8+
9+
mzeros(rows, cols) do A
10+
printf(A)
11+
end
12+
mones(Int, rows, cols) do A
13+
printf(A)
14+
end
15+
mfill(3.141592, rows, cols) do A
16+
printf(A)
17+
end
18+
end
19+
20+
# Attempt to compile
21+
path = compile_executable(withmallocarray, (Int64, Ptr{Ptr{UInt8}}), "./")

test/testmallocarray.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,31 @@
203203
@test A == B
204204
free(A)
205205
free(B)
206+
207+
## --- test "withmallocarray" pattern
208+
209+
s = MallocArray(Int64, 2, 2) do A
210+
A .= 1
211+
sum(A)
212+
end
213+
@test s === 4
214+
215+
s = mones(2, 2) do A
216+
sum(A)
217+
end
218+
@test s === 4.0
219+
220+
s = mzeros(2, 2) do A
221+
sum(A)
222+
end
223+
@test s === 0.0
224+
225+
s = meye(2) do A
226+
sum(A)
227+
end
228+
@test s === 2.0
229+
230+
s = mfill(3.14, 2, 2) do A
231+
sum(A)
232+
end
233+
@test s === 12.56

test/teststaticcompiler.jl

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ scratch = tempdir()
44
cd(scratch)
55

66
## --- Times table, file IO, mallocarray
7-
87
let
98
# Attempt to compile
109
# We have to start a new Julia process to get around the fact that Pkg.test
@@ -38,13 +37,36 @@ let
3837
@test fread!(szeros(Int, 5,5), c"table.b") == (1:5)*(1:5)'
3938
end
4039

41-
## --- Random number generation
40+
## --- "withmallocarray"-type do-block pattern
41+
let
42+
# Compile...
43+
status = -1
44+
try
45+
isfile("withmallocarray") && rm("withmallocarray")
46+
status = run(`julia --compile=min $testpath/scripts/withmallocarray.jl`)
47+
catch e
48+
@warn "Could not compile $testpath/scripts/withmallocarray.jl"
49+
println(e)
50+
end
51+
@test isa(status, Base.Process)
52+
@test isa(status, Base.Process) && status.exitcode == 0
53+
54+
# Run...
55+
println("5x5 uniform random matrix:")
56+
status = -1
57+
try
58+
status = run(`./withmallocarray 5 5`)
59+
catch e
60+
@warn "Could not run $(scratch)/withmallocarray"
61+
println(e)
62+
end
63+
@test isa(status, Base.Process)
64+
@test isa(status, Base.Process) && status.exitcode == 0
65+
end
4266

67+
## --- Random number generation
4368
let
44-
# Attempt to compile...
45-
# We have to start a new Julia process to get around the fact that Pkg.test
46-
# disables `@inbounds`, but ironically we can use `--compile=min` to make that
47-
# faster.
69+
# Compile...
4870
status = -1
4971
try
5072
isfile("rand_matrix") && rm("rand_matrix")
@@ -70,10 +92,7 @@ let
7092
end
7193

7294
let
73-
# Attempt to compile...
74-
# We have to start a new Julia process to get around the fact that Pkg.test
75-
# disables `@inbounds`, but ironically we can use `--compile=min` to make that
76-
# faster.
95+
# Compile...
7796
status = -1
7897
try
7998
isfile("randn_matrix") && rm("randn_matrix")
@@ -103,10 +122,9 @@ let
103122
end
104123

105124
## --- Test LoopVectorization integration
106-
107125
@static if LoopVectorization.VectorizationBase.has_feature(Val{:x86_64_avx2})
108126
let
109-
# Attempt to compile...
127+
# Compile...
110128
status = -1
111129
try
112130
isfile("loopvec_product") && rm("loopvec_product")
@@ -134,7 +152,7 @@ end
134152
end
135153

136154
let
137-
# Attempt to compile...
155+
# Compile...
138156
status = -1
139157
try
140158
isfile("loopvec_matrix") && rm("loopvec_matrix")
@@ -165,7 +183,7 @@ let
165183
end
166184

167185
let
168-
# Attempt to compile...
186+
# Compile...
169187
status = -1
170188
try
171189
isfile("loopvec_matrix_stack") && rm("loopvec_matrix_stack")
@@ -196,7 +214,7 @@ end
196214
## --- Test string handling
197215

198216
let
199-
# Attempt to compile...
217+
# Compile...
200218
status = -1
201219
try
202220
isfile("print_args") && rm("print_args")
@@ -224,5 +242,3 @@ end
224242
## --- Clean up
225243

226244
cd(testpath)
227-
228-
## ---

0 commit comments

Comments
 (0)