plar / go-adaptive-radix-tree

Adaptive Radix Trees implemented in Go

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Optimization: proposal for reducing memory usage

CodingCrush opened this issue · comments

  • as the base part of node, numChildren and prefixLen could be modified to uint8 to save 6 bytes each node except leaf;

type node struct { numChildren int prefixLen int prefix prefix }

  • as the Kind type, int is also unnecessary, uint8 is enough too, this optimization will save 3 bytes for each art-node
    type Kind int

So if I understand your proposal; this will limit the maximum prefix length to 256 bytes? Its not super clear to me how this translate into a limitation of maximum key size itself?

Sorry, I misunderstood the prefixLen field

What about performance? Did you try to run benchmarks?

I took a simple test just now.
after inserting 650250 ip(key: 192.168.1.1, value: uint32(1)),

  • the original tree consumes 93.2MB;
  • the optimized tree consumes 91.0MB, (with uint8 Kind and uint8 numChildren)
  • the map consumes 57.2MB;

the improvement is not particularly obvious, but very easy

I think you've already made a case for the memory optimization; But like @plar says I'm also interested in the performance implications here? Can you run the existing benchmarks with the patch?

I'm also personally still interested in the impact this has on maximum key sizes and how this impacts usability. I use this library in Bitcask with configurable maximum key sizes.

@prologic
The benchmark is shown as follows without changing the type of prefixLen in node
I am curious about why the performance difference is so obvious.
In addition, the max number children number of node256 is 257, but it seems that uint8 numChildren does not affect the usage

  • uint8

goos: darwin
goarch: amd64
pkg: github.com/plar/go-adaptive-radix-tree
BenchmarkWordsTreeInsert-4 3 429901795 ns/op
BenchmarkWordsTreeSearch-4 5 335040413 ns/op
BenchmarkWordsTreeIterator-4 2000000000 0.05 ns/op
BenchmarkWordsTreeForEach-4 2000000000 0.05 ns/op
BenchmarkUUIDsTreeInsert-4 10 179928335 ns/op
BenchmarkUUIDsTreeSearch-4 10 124883234 ns/op
BenchmarkUUIDsTreeIterator-4 2000000000 0.02 ns/op
BenchmarkUUIDsTreeForEach-4 2000000000 0.06 ns/op
BenchmarkHSKTreeInsert-4 100 12572752 ns/op
BenchmarkHSKTreeSearch-4 100 10294600 ns/op
BenchmarkHSKTreeIterator-4 2000000000 0.00 ns/op
BenchmarkHSKTreeForEach-4 2000000000 0.00 ns/op

  • int

goos: darwin
goarch: amd64
pkg: github.com/plar/go-adaptive-radix-tree
BenchmarkWordsTreeInsert-4 2 502975809 ns/op
BenchmarkWordsTreeSearch-4 3 363666671 ns/op
BenchmarkWordsTreeIterator-4 2000000000 0.06 ns/op
BenchmarkWordsTreeForEach-4 1000000000 0.12 ns/op
BenchmarkUUIDsTreeInsert-4 5 213343879 ns/op
BenchmarkUUIDsTreeSearch-4 10 146526269 ns/op
BenchmarkUUIDsTreeIterator-4 2000000000 0.02 ns/op
BenchmarkUUIDsTreeForEach-4 2000000000 0.02 ns/op
BenchmarkHSKTreeInsert-4 100 11131454 ns/op
BenchmarkHSKTreeSearch-4 300 4461155 ns/op
BenchmarkHSKTreeIterator-4 2000000000 0.00 ns/op
BenchmarkHSKTreeForEach-4 2000000000 0.00 ns/op
PASS

@CodingCrush There are multiple places where the memory usage (reduce size of multiple fields and get rid of an artNode structure) and performance(use SIMD instructions) can be improved but I don’t have time to implement it now.