lib/uint64set: remove memory allocation in bucket16.appendTo when sorting smallPool

This commit is contained in:
Aliaksandr Valialkin 2021-02-16 15:31:38 +02:00
parent 18305caadb
commit da05c10544

View File

@ -743,9 +743,11 @@ const (
type bucket16 struct { type bucket16 struct {
bits *[wordsPerBucket]uint64 bits *[wordsPerBucket]uint64
smallPoolLen int smallPoolLen int
smallPool [56]uint16 smallPool [smallPoolSize]uint16
} }
const smallPoolSize = 56
func (b *bucket16) isZero() bool { func (b *bucket16) isZero() bool {
return b.bits == nil && b.smallPoolLen == 0 return b.bits == nil && b.smallPoolLen == 0
} }
@ -927,22 +929,20 @@ func (b *bucket16) delFromSmallPool(x uint16) bool {
func (b *bucket16) appendTo(dst []uint64, hi uint32, hi16 uint16) []uint64 { func (b *bucket16) appendTo(dst []uint64, hi uint32, hi16 uint16) []uint64 {
hi64 := uint64(hi)<<32 | uint64(hi16)<<16 hi64 := uint64(hi)<<32 | uint64(hi16)<<16
if b.bits == nil { if b.bits == nil {
// Use smallPoolSorter instead of sort.Slice here in order to reduce memory allocations.
sps := smallPoolSorterPool.Get().(*smallPoolSorter)
// Sort a copy of b.smallPool, since b must be readonly in order to prevent from data races // Sort a copy of b.smallPool, since b must be readonly in order to prevent from data races
// when b.appendTo is called from concurrent goroutines. // when b.appendTo is called from concurrent goroutines.
smallPool := b.smallPool sps.smallPool = b.smallPool
sps.a = sps.smallPool[:b.smallPoolLen]
// Use uint16Sorter instead of sort.Slice here in order to reduce memory allocations. if len(sps.a) > 1 && !sort.IsSorted(sps) {
a := uint16SorterPool.Get().(*uint16Sorter) sort.Sort(sps)
*a = uint16Sorter(smallPool[:b.smallPoolLen])
if len(*a) > 1 && !sort.IsSorted(a) {
sort.Sort(a)
} }
for _, v := range *a { for _, v := range sps.a {
x := hi64 | uint64(v) x := hi64 | uint64(v)
dst = append(dst, x) dst = append(dst, x)
} }
*a = nil smallPoolSorterPool.Put(sps)
uint16SorterPool.Put(a)
return dst return dst
} }
var wordNum uint64 var wordNum uint64
@ -966,20 +966,25 @@ func (b *bucket16) appendTo(dst []uint64, hi uint32, hi16 uint16) []uint64 {
return dst return dst
} }
var uint16SorterPool = &sync.Pool{ var smallPoolSorterPool = &sync.Pool{
New: func() interface{} { New: func() interface{} {
return &uint16Sorter{} return &smallPoolSorter{}
}, },
} }
type uint16Sorter []uint16 type smallPoolSorter struct {
smallPool [smallPoolSize]uint16
func (s uint16Sorter) Len() int { return len(s) } a []uint16
func (s uint16Sorter) Less(i, j int) bool {
return s[i] < s[j]
} }
func (s uint16Sorter) Swap(i, j int) {
s[i], s[j] = s[j], s[i] func (sps *smallPoolSorter) Len() int { return len(sps.a) }
func (sps *smallPoolSorter) Less(i, j int) bool {
a := sps.a
return a[i] < a[j]
}
func (sps *smallPoolSorter) Swap(i, j int) {
a := sps.a
a[i], a[j] = a[j], a[i]
} }
func getWordNumBitMask(x uint16) (uint16, uint64) { func getWordNumBitMask(x uint16) (uint16, uint64) {