-
Notifications
You must be signed in to change notification settings - Fork 586
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
AssertionError in floats(max_value=0, exclude_max=True) when "denormals-are-zero" processor flag is set
#3092
Comments
|
Oh no. This is going to be "fun" for whoever tracks it down - likely to include int/float casting and the difference between |
|
I've spent a while trying to reproduce this, without any success - perhaps some of our recent changes for subnormal numbers have fixed it? It's also possible that your problem was due to using a Python interpreter compiled with unsafe optimizations like e.g. |
|
I was seeing the same issue and boiled it down to something about gevent: import gevent
from hypothesis import strategies as st
# raises the same assertion error
print(st.floats(max_value=0, exclude_max=True).example())One workaround is to specify I'm not sure what exactly about gevent would cause this. It might be something about its C extensions, as the change in behavior seems to happen right after I tried building and importing a helloworld module from cython's tutorial and it didn't cause the assertion error. How I got here: Boiled it down to a difference in the result of this expression from $ python -c 'import struct; print(struct.unpack("!d", struct.pack("!q", 1)))'
(5e-324,)
$ python manage.py shell --command 'import struct; print(struct.unpack("!d", struct.pack("!q", 1)))'
(0.0,)Got a list of imported modules: python manage.py shell --command 'import sys; [print(m) for m in sys.modules]' > imports.txtand bisected that by inserting this snippet at the top of the imported module at each bisection point: import struct, sys
print(struct.unpack("!d", struct.pack("!q", 1)), __name__, "*" * 30)
print(list(sys.modules.keys()))The unpacked value is non-zero at least until https://github.com/gevent/gevent/blob/21.12.0/src/gevent/_config.py#L699 |
|
🙏 Thank you so much for tracking this down! A small repro like this makes all the difference 🙏 |
|
Unfortunately it looks like something is setting a flush-to-zero flag in the floating-point module somewhere, which I had hoped was a statically configured thing. See also #3152, #3155, and #3156 - the Either way we should also report this upstream, I'd expect Gevent to want to fix this even if we and Django both work around it. (Equally unfortunately, I can't reproduce this on my machine 😭) |
|
Found a handy package that lets you set the flush-to-zero flag on the fly, and wrote test cases that fail in GitHub Actions. (The branch modifies the main workflow to be able to quickly run those tests in my forked repo. test-win/test-osx jobs also fail because the aforementioned package hasn't been added to a shared requirements.txt file) The tests show that gevent's latest release is actually compiled with a flag ( Either it's not taking effect, or something else is setting some flag. Adding
Might have something to do with the CPU in use? I'm on Intel Core i7-10810U. |
AssertionError in floats(max_value=0, exclude_max=True) when "denormals-are-zero" processor flag is set
|
OK, sounds like this is already fixed with the latest versions of upstream... and all that's left is to decide what we should do about it in Hypothesis. I think the best available option is to make |
Yep I like that. I had tried setting |
|
I'm new to thinking about this problem space; my confidence level isn't high and this comment is more like thinking out loud:
In my case, the
I first thought of automatically adjusting the default
It appears to be that this flag isn't actually taking effect in terms of disabling DAZ/FTZ flags because of how gcc links in internal code that enables them. I'm going to report upstream later. |
Yeah, I think the best answer here is to encourage end-users to use FWIW I also expect this to be very rare; the only use-case I've ever had reported was relatively recently - "GPUs don't support subnormals in the default mode" - and that seems unlikely to intersect with downstream library strategies in e.g. Pydantic.
Ah, yeah, that would do it! On one level I do understand why people turn to undefined behaviour (performance! seems to work!), but it always ends up being a source of deep sadness... |
|
I don't think we should touch these process-wide flags, but we could reasonably check for them on any use of floats with |
From the normal Python shell and ipython, this works:
But from
./manage.py shelland while actually running Django normally, it fails:I'm definitely using the same installation of hypothesis from the same virtualenv:
I'm using Django==3.1.13
The text was updated successfully, but these errors were encountered: