Skip to content

Commit 9b68b44

Browse files
committed
fix append memory allocations
Old implementation was focusing on having full control over capacity growth. This caused enormous memory allocations: 1.6GB to load 1.3MB sample. This fix uses built-in append function to grow slice capacity.
1 parent c5030ea commit 9b68b44

File tree

2 files changed

+19
-11
lines changed

2 files changed

+19
-11
lines changed

signal.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package signal
44

55
import (
66
"math"
7+
"reflect"
78
"time"
89
)
910

@@ -624,3 +625,9 @@ func ReadStripedUint(src Unsigned, dst [][]uint) (read int) {
624625
}
625626
return
626627
}
628+
629+
// alignCapacity ensures that buffer capacity is aligned with number of
630+
// channels.
631+
func alignCapacity(s interface{}, channels, cap int) {
632+
reflect.ValueOf(s).Elem().SetCap(cap - cap%channels)
633+
}

templates/signal.tmpl

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,23 @@ func (s {{ .Name }}) Sample(i int) {{ .SampleType }} {
6060
return {{ .SampleType }}(s.buffer[i])
6161
}
6262

63-
// Append appends [0:Length] samples from src to current buffer and returns new
64-
// {{ .Interface }} buffer. Both buffers must have same number of channels and bit depth,
65-
// otherwise function will panic. If current buffer doesn't have enough capacity,
66-
// new buffer will be allocated with capacity of both sources.
63+
// Append appends [0:Length] samples from src to current buffer and returns
64+
// new {{ .Interface }} buffer. Both buffers must have same number of channels and
65+
// bit depth, otherwise function will panic.
6766
func (s {{ .Name }}) Append(src {{ .Interface }}) {{ .Interface }} {
6867
mustSameChannels(s.Channels(), src.Channels()){{if ne .Interface "Floating"}}
6968
mustSameBitDepth(s.BitDepth(), src.BitDepth()){{end}}
69+
offset := s.Len()
7070
if s.Cap() < s.Len()+src.Len() {
71-
// allocate and append buffer with cap of both sources capacity;
72-
s.buffer = append(make([]{{ .Builtin }}, 0, s.Cap()+src.Cap()), s.buffer...)
71+
s.buffer = append(s.buffer, make([]{{ .Builtin }}, src.Len())...)
72+
} else {
73+
s.buffer = s.buffer[:s.Len()+src.Len()]
7374
}
74-
result := {{ .Interface }}(s)
7575
for i := 0; i < src.Len(); i++ {
76-
result = result.AppendSample(src.Sample(i))
76+
s.SetSample(i+offset, src.Sample(i))
7777
}
78-
return result
78+
alignCapacity(&s.buffer, s.Channels(), s.Cap())
79+
return s
7980
}
8081

8182
// Slice slices buffer with respect to channels.
@@ -183,10 +184,10 @@ func Test{{ .Name }}(t *testing.T) {
183184
signal.Allocator{
184185
Channels: 3,
185186
Capacity: 2,
186-
}.{{ .Name }}({{if ne .Interface "Floating"}}signal.{{ .MaxBitDepth }}{{end}}).Append(input).Slice(1, 3),
187+
}.{{ .Name }}({{if ne .Interface "Floating"}}signal.{{ .MaxBitDepth }}{{end}}).Append(input.Slice(1, 3)),
187188
expected{
188189
length: 2,
189-
capacity: 4,
190+
capacity: 2,
190191
data: [][]{{ .Builtin }}{
191192
{0, 0},
192193
{2, 3},

0 commit comments

Comments
 (0)