Skip to content

Commit 5d9d888

Browse files
authored
Fix: ncon should add allocator_checkpoint! and allocator_reset! to avoid leaking buffer space (#276)
* fix ncon memory leak * bump v5.6.2
1 parent a1753ae commit 5d9d888

3 files changed

Lines changed: 26 additions & 2 deletions

File tree

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "TensorOperations"
22
uuid = "6aa20fa7-93e2-5fca-9bc0-fbd0db3c71a2"
3-
version = "5.6.1"
3+
version = "5.6.2"
44
authors = ["Lukas Devos <lukas.devos@ugent.be>", "Maarten Van Damme <maartenvd1994@gmail.com>", "Jutho Haegeman <jutho.haegeman@ugent.be>"]
55

66
[deps]

src/implementation/ncon.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,16 @@ function ncon(
4242
tensors, network = resolve_traces(tensors, network)
4343
tree = order === nothing ? ncontree(network) : indexordertree(network, order)
4444

45+
allocator = haskey(kwargs, :allocator) ? kwargs[:allocator] : DefaultAllocator()
46+
cp = allocator_checkpoint!(allocator)
47+
4548
A, IA, conjA = contracttree(tensors, network, conjlist, tree[1]; kwargs...)
4649
B, IB, conjB = contracttree(tensors, network, conjlist, tree[2]; kwargs...)
4750
IC = tuple(output′...)
4851
C = tensorcontract(IC, A, IA, conjA, B, IB, conjB; kwargs...)
49-
allocator = haskey(kwargs, :allocator) ? kwargs[:allocator] : DefaultAllocator()
5052
tree[1] isa Int || tensorfree!(A, allocator)
5153
tree[2] isa Int || tensorfree!(B, allocator)
54+
allocator_reset!(allocator, cp)
5255
return length(IC) == 0 ? tensorscalar(C) : C
5356
end
5457

test/allocator.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,25 @@ using LinearAlgebra
9999
tensoralloc(Array{UInt8, 2}, (L + 1, 1), Val(true), buffer)
100100
@test length(buffer) > L
101101
end
102+
103+
@testset "ncon does not leak buffer space" begin
104+
buffer = BufferAllocator()
105+
A = randn(5, 5)
106+
B = randn(5, 5)
107+
C = randn(5, 5)
108+
# chain contraction A*B*C -> at least one intermediate tensor allocated as temp
109+
R = ncon([A, B, C], [[-1, 1], [1, 2], [2, -2]]; allocator = buffer)
110+
@test R A * B * C
111+
# offset must return to 0: intermediates were reclaimed via allocator_reset!
112+
@test buffer.offset == 0
113+
@test isempty(buffer)
114+
115+
# repeated calls must not grow the high-water mark beyond a single call's needs
116+
max1 = buffer.max_offset
117+
for _ in 1:5
118+
ncon([A, B, C], [[-1, 1], [1, 2], [2, -2]]; allocator = buffer)
119+
end
120+
@test buffer.offset == 0
121+
@test buffer.max_offset == max1
122+
end
102123
end

0 commit comments

Comments
 (0)