Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Opimtize key tree stemming by using maps instead of sets #3963

Merged
merged 1 commit into from Mar 21, 2022

Conversation

nickva
Copy link
Contributor

@nickva nickva commented Mar 21, 2022

sets to due to a compiler bug in 22 consumes too much memory and is slower on Erlang 22+

Reproducer: https://gist.github.com/nickva/ddc499e6e05678faf20d344c6e11daaa

With sets:

couch_key_tree:gen_and_stem().
{8,6848.812683105469}

With maps:

couch_key_tree:gen_and_stem().
{0,544.000732421875}

sets to due to a compiler bug in 22 consumes too much memory and is slower on Erlang 22+

Reproducer: https://gist.github.com/nickva/ddc499e6e05678faf20d344c6e11daaa

With sets:
```
couch_key_tree:gen_and_stem().
{8,6848.812683105469}
```

With maps:
```
couch_key_tree:gen_and_stem().
{0,544.000732421875}
```
@davisp
Copy link
Member

davisp commented Mar 21, 2022

I'd also note that this improves performance across the board. Using maps on 20 and 21 also improves against current baseline.

+1

@nickva nickva merged commit 91de482 into 3.x Mar 21, 2022
@nickva nickva deleted the optimize-key-tree-using-maps branch March 21, 2022 18:17
@nickva
Copy link
Contributor Author

nickva commented Mar 22, 2022

Trying the optimization with a production revision tree with 6638 live conflicts.

length(couch_key_tree:get_all_leafs(Tree)).
6638

Measured time to run couch_key_tree:stem(Tree, 1000)

Before this commit

Erlang Version Time (sec) Memory (GBs)
20 221 1.2
23 1382 45

After this commit

Erlang Version Time (sec) Memory (GBs)
20 3 1.2
23 3 1.3

In summary, on Erlang 23, we got a nice 460x speedup and 34x memory usage reduction

@kocolosk
Copy link
Member

Now you're just showing off 😉 Nice work!

nickva added a commit that referenced this pull request Mar 24, 2022
`couch_key_tree:stem/2`, as seen in
#3963, has a potential to consume quite a
bit of memory. Replacing sets with maps helped in that case however, since
stemming has a non-tail recursive section, there is a chance in future versions
of Erlang to experience the same behavior again.

As a safeguard, add a memory limit test by stemming a larger conflicted rev
tree while limiting the maximum process heap size. For that, use the nifty
`max_heap_size` process flag, which ensures a process is killed if it starts
using too much memory.

To reduce the flakiness, use a determistic tree shape by using a hard-coded
seed value, and leave a decent margin for error for the limit.

Ref: #3963
nickva added a commit that referenced this pull request Mar 24, 2022
`couch_key_tree:stem/2`, as seen in
#3963, has a potential to consume quite a
bit of memory. Replacing sets with maps helped in that case however, since
stemming has a non-tail recursive section, there is a chance in future versions
of Erlang to experience the same behavior again.

As a safeguard, add a memory limit test by stemming a larger conflicted rev
tree while limiting the maximum process heap size. For that, use the nifty
`max_heap_size` process flag, which ensures a process is killed if it starts
using too much memory.

To reduce the flakiness, use a deterministic tree shape by using a hard-coded
seed value and leave a decent margin of error for the memory limit.

Ref: #3963
nickva added a commit that referenced this pull request Mar 25, 2022
`couch_key_tree:stem/2`, as seen in
#3963, has a potential to consume quite a
bit of memory. Replacing sets with maps helped in that case however, since
stemming has a non-tail recursive section, there is a chance in future versions
of Erlang to experience the same behavior again.

As a safeguard, add a memory limit test by stemming a larger conflicted rev
tree while limiting the maximum process heap size. For that, use the nifty
`max_heap_size` process flag, which ensures a process is killed if it starts
using too much memory.

To reduce the flakiness, use a deterministic tree shape by using a hard-coded
seed value and leave a decent margin of error for the memory limit.

Ref: #3963
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants