-
Notifications
You must be signed in to change notification settings - Fork 222
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
Improve performance with GMP library. #44
Conversation
ans += 1 | ||
x &= x - 1 | ||
return ans | ||
return popcount(self.value ^ another.value) |
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.
Hi, thanks for the pull request.
I'm trying to understand the popcount
here.
Have you done some performance test to show that popcount
is more efficient?
Or maybe you have the source code of popcount
?
I'm trying to find it out, but not found anything about its implementation yet.
:-)
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.
popcount
is used to get the number of 1
in binary.
gmpy2
is using GMP
libary's popcount
function. There is also a cpu instruction named POPCNT
, I guess GMP
should be able to call it. I cpu instruction should be much faster than iterate the bit array to find the 1
s.
I've show the performance test in #43, it's 10x faster.
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.
Thanks!, that helps a lot and it makes sense now. Just curious why the 2 methods produced different results because the old method is to get the number of 1 in binary too. 🙂
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.
By the way, one more thing, in case cpu doesn't have that instruction popcount, can it fall back to less efficient ways to get the same result? 🙂
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.
The distance
function produce same result 19
.
But the two version produce different value, 864692470817131398
and 7048486158682030128
respectively. Because new method treat the first bit as most significant bit. For example, when v
is 001
, the original method produces 4
, but the new method produces 1
.
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.
Don't worry, GMP
library should always return the right result regardless of which cpu is using.
simhash/__init__.py
Outdated
if v[i] > 0: | ||
ans |= masks[i] | ||
self.value = ans | ||
binary_str = ''.join(['0' if i <= 0 else '1' for i in v]) |
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.
If we don't change this, the popcount will still work, right? The join command here is O(n) the same complexity as the old implementation. May I ask why you change 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.
Hi KK, thanks again for replying.
I see this is another improvement you are trying to make.
Could you move this change into a separate pull request?
I just want to make this change minimal so that it's easy to test and I'll have much higher confidence to merge if so.
Thanks.
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.
Okay, I've revert the value calculation.
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.
Thanks, bebound. Can you update the unit tests as well? Because right now the build is failing. I'm not sure why the build result is not showing here, but I'll check later. (By right, each commit will trigger a CI build and the result will show here)
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.
Sorry, I forget to rollback the value in test. It should work now.
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.
Travis said I forget to add gmpy2
as dependency, I'll fix that.
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.
Travis has been fixed.
It should work. I change this to make the code cleaner and more intuitive. In general, binary str 0001 represent 1.
…On Apr 20, 2020, 00:21 +0800, Leon , wrote:
@leonsim commented on this pull request.
In simhash/__init__.py:
> @@ -105,20 +107,12 @@ def build_by_features(self, features):
w = f[1]
for i in range(self.f):
v[i] += w if h & masks[i] else -w
- ans = 0
- for i in range(self.f):
- if v[i] > 0:
- ans |= masks[i]
- self.value = ans
+ binary_str = ''.join(['0' if i <= 0 else '1' for i in v])
If we don't change this, the popcount will still work, right? The join command here is O(n) the same complexity as the old implementation. May I ask why you change this?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub, or unsubscribe.
|
@bebound Thanks for your work! 👍 |
As #43 mentions, the simhash.value will change, but distance should be the same.
I've test on python3.7, python2 should work
output: