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

[Go] Dictionary unifier uses unnecessarily expensive getvalFn #37306

Closed
brancz opened this issue Aug 22, 2023 · 5 comments · Fixed by #37309
Closed

[Go] Dictionary unifier uses unnecessarily expensive getvalFn #37306

brancz opened this issue Aug 22, 2023 · 5 comments · Fixed by #37309

Comments

@brancz
Copy link
Contributor

brancz commented Aug 22, 2023

Describe the enhancement requested

Our profiling data shows clearly that even though dictionary unification is working brilliantly, there is still plenty of CPU time that is used that is unnecessary. Take this profiling data: https://pprof.me/6681ca5

This shows that ~43% is spent because of convTslice within getvalFn, because the value has to be treated as an interface{} and is then subsequently added to the MemoTable using non-type-safe GetOrInsert.

I see 3 potential ways forward:

  1. Somehow optimize this away entirely, though I don't see how.
  2. Offer a specific DictionaryUnifier per type (these could be added one by one as they're needed).
  3. Move hashing out of the internal package so that people can build their own DictionaryUnifiers.

@zeroshade thoughts?

Component(s)

Go

@brancz
Copy link
Contributor Author

brancz commented Aug 22, 2023

I think I would tend towards 2 and 3, but don't feel strongly. Either way, I'm already starting to implement a BinaryDictionaryUnifier, which I'm happy to contribute.

brancz added a commit to brancz/arrow that referenced this issue Aug 22, 2023
The "generic" dictionary unifier is fine for starting out, but causes
unnecessary CPU cycles because of the `getvalFn` returning `interface{}`
and the ramifications of it.

Fixes apache#37306
brancz added a commit to brancz/arrow that referenced this issue Aug 22, 2023
The "generic" dictionary unifier is fine for starting out, but causes
unnecessary CPU cycles because of the `getvalFn` returning `interface{}`
and the ramifications of it.

Fixes apache#37306
brancz added a commit to brancz/arrow that referenced this issue Aug 22, 2023
The "generic" dictionary unifier is fine for starting out, but causes
unnecessary CPU cycles because of the `getvalFn` returning `interface{}`
and the ramifications of it.

Fixes apache#37306
brancz added a commit to brancz/arrow that referenced this issue Aug 22, 2023
The "generic" dictionary unifier is fine for starting out, but causes
unnecessary CPU cycles because of the `getvalFn` returning `interface{}`
and the ramifications of it.

Fixes apache#37306
@zeroshade
Copy link
Member

So, @brancz I think it's been long enough at this point that I'd be fine with updating the Arrow lib to go1.18+ and introducing generics right into the main library (since go1.21 is officially out, the standard would be that we can go up to 1.19 safely). Do you want to try your hand at upgrading the unifier / memo table / etc. to fully leverage generics for the performance improvements?

@brancz
Copy link
Contributor Author

brancz commented Aug 22, 2023

I have a feeling you must have thought about this much much longer than I have, for me that's a pretty unknown amount of time to spend, and I won't be able to get to something like that for the next 1-2 months.

@zeroshade
Copy link
Member

Haha, perfectly fine. It's on my list of things to do, particularly because of the performance potential. In the meantime, I agree with you that both solutions 2 and 3 are viable ideas. I'll definitely take a look at review the PR you added. I guess whichever one of us can manage to get to this first will put up a PR for it 😄

If I do get around to this, I'll make sure to tag you on the PR since I'd be interested to see if you notice any performance improvements in your use cases (might even be interesting to see if you could simplify some of your use cases enough to contribute potential benchmark functions).

@brancz
Copy link
Contributor Author

brancz commented Aug 22, 2023

If I do get around to this, I'll make sure to tag you on the PR since I'd be interested to see if you notice any performance improvements in your use cases (might even be interesting to see if you could simplify some of your use cases enough to contribute potential benchmark functions).

I wish ... unfortunately I don't even have local benchmarks for my code for this. It's all coming from profiling in production and using that data to inform changes.

Haha, perfectly fine. It's on my list of things to do, particularly because of the performance potential. In the meantime, I agree with you that both solutions 2 and 3 are viable ideas. I'll definitely take a look at review the PR you added. I guess whichever one of us can manage to get to this first will put up a PR for it 😄

Amazing! Sounds good!

brancz added a commit to brancz/arrow that referenced this issue Aug 26, 2023
The "generic" dictionary unifier is fine for starting out, but causes
unnecessary CPU cycles because of the `getvalFn` returning `interface{}`
and the ramifications of it.

Fixes apache#37306
@zeroshade zeroshade added this to the 14.0.0 milestone Aug 28, 2023
zeroshade pushed a commit that referenced this issue Aug 28, 2023
The "generic" dictionary unifier is fine for starting out, but causes unnecessary CPU cycles because of the `getvalFn` returning `interface{}` and the ramifications of it.

Fixes #37306

### Rationale for this change

See #37306

### What changes are included in this PR?

An optimized version of a unifier for binary dictionaries.

### Are these changes tested?

Tested by using it within [Parca](https://github.com/parca-dev/parca).

### Are there any user-facing changes?

This is a new API.
* Closes: #37306

Authored-by: Frederic Branczyk <fbranczyk@gmail.com>
Signed-off-by: Matt Topol <zotthewizard@gmail.com>
loicalleyne pushed a commit to loicalleyne/arrow that referenced this issue Nov 13, 2023
The "generic" dictionary unifier is fine for starting out, but causes unnecessary CPU cycles because of the `getvalFn` returning `interface{}` and the ramifications of it.

Fixes apache#37306

### Rationale for this change

See apache#37306

### What changes are included in this PR?

An optimized version of a unifier for binary dictionaries.

### Are these changes tested?

Tested by using it within [Parca](https://github.com/parca-dev/parca).

### Are there any user-facing changes?

This is a new API.
* Closes: apache#37306

Authored-by: Frederic Branczyk <fbranczyk@gmail.com>
Signed-off-by: Matt Topol <zotthewizard@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants