-
-
Notifications
You must be signed in to change notification settings - Fork 18.3k
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
PERF: Improve merge performance #57559
base: main
Are you sure you want to change the base?
Conversation
@@ -1142,6 +1149,7 @@ cdef class StringHashTable(HashTable): | |||
# ignore_na is True), we can skip the actual value, and | |||
# replace the label with na_sentinel directly | |||
labels[i] = na_sentinel | |||
seen_na = True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of trying to find this iterating by element can we get the same performance by querying up front for missing values? That approach would work better in the future where we are more arrow based
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wouldn't we expect a two-pass implementation to be slower? i dont think we should be making decisions based on a potential arrow-based future since that would likely need a completely separate implementation anyway
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Arrow strings are using a completely different code path, this is just for our own strings
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wouldn't we expect a two-pass implementation to be slower? i
Generally I would expect a two pass solution to be faster. Our nulll-checking implementations are pretty naive and always go elementwise with a boolean value. The Arrow implementation iterates 64 bits at a time, so checking for NA can be up to 64x as fast as this kind of loop. I'm not sure what NumPy does internally but with a byte mask that same type of logic would be up to 8x as fast.
By separating that out to a different has_na().any()
type of check you let other libraries determine that much faster than we can
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be clear not a blocker for now; just something to think about as we make our code base more Arrow friendly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Arrow strings are using a completely different code path, this is just for our own strings
As I said, arrow dispatches to pyarrow compute functions for those things, so it won't impact this part for now anyway
@@ -1437,6 +1449,8 @@ cdef class PyObjectHashTable(HashTable): | |||
idx = self.table.vals[k] | |||
labels[i] = idx | |||
|
|||
if return_inverse and return_labels_only: | |||
return labels.base, seen_na # .base -> underlying ndarray |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the second argument returned by this is either a bool or an ndarray right? Instead of having dynamic return types like that I think it would be better to just pass in a reference to seen_na
- the caller can choose to ignore the result altogether if they'd like. But that way you don't need a return_labels_only
argument and can be consistent in what is returned
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this was my first idea as well, but it isn't a good idea. We drop the result but we still set an internal variable that signals that there is an external view created, which triggers a copy later in the process because we call into the same hashtable again. Avoiding this copy is part of the performance improvement, so we can't use the same signature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand how passing the seen_na
variable by reference as opposed to having a dynamic return type affects that. That seems like a code organization issue outside of this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That doesn't matter, but returning the same result as when return_labels_only=False
matters, so we need another if condition anyway.
@WillAyd good to merge? |
This pull request is stale because it has been open for thirty days with no activity. Please update and respond to this comment if you're still interested in working on this. |
doc/source/whatsnew/vX.X.X.rst
file if fixing a bug or adding a new feature.this avoids a bunch of unnecessary checks, might be worth it