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

Tests crash on i386 #565

Closed
nabijaczleweli opened this issue Mar 23, 2020 · 11 comments
Closed

Tests crash on i386 #565

nabijaczleweli opened this issue Mar 23, 2020 · 11 comments
Labels

Comments

@nabijaczleweli
Copy link
Contributor

nabijaczleweli commented Mar 23, 2020

System information

SolveSpace version: current HEAD (e355a09)

Operating system: Debian sid i386 + libc6 2.30-2

Expected behavior

Tests run

Actual behavior

nabijaczleweli@nabtop:~/src/solvespace/build$ bin/solvespace-testsuite
[...]
test/constraint/pt_face_distance/test.cpp:21: FAILED: render doesn't match reference; 2 (0.00%) pixels differ
  NG   test constraint/pt_face_distance/reference_roundtrip
[...]
File ../test/harness.cpp, line 112, function PrepareSavefile:
Assertion failed: value.size() == newValue.size().
Message: Expected no change in value length.
Backtrace support not compiled in.
Aborted

Additional information

nabijaczleweli@nabtop:~/src/solvespace/build$ bin/solvespace-testsuite
Missing (absent) translation for group-name'#references'
Missing (absent) translation for group-name'sketch-in-plane'
  OK   test constraint/length_difference/normal_migrate_from_v22
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
  OK   test constraint/pt_line_distance/free_in_3d_roundtrip
  OK   test core/path/from_raw
  OK   test constraint/proj_pt_distance/reference_migrate_from_v22
  OK   test constraint/where_dragged/free_in_3d_roundtrip
  OK   test constraint/horizontal/line_migrate_from_v22
  OK   test core/path/extension
  OK   test constraint/length_difference/normal_roundtrip
  OK   test constraint/same_orientation/normal_migrate_from_v22
  OK   test constraint/equal_angle/other_roundtrip
  OK   test constraint/symmetric/normal_migrate_from_v22
  OK   test constraint/pt_pt_distance/reference_roundtrip
  OK   test constraint/equal_line_arc_len/tau
  OK   test core/expr/literal
  OK   test constraint/pt_on_line/normal_migrate_from_v22
  OK   test constraint/pt_line_distance/reference_migrate_from_v22
  OK   test constraint/pt_face_distance/normal_migrate_from_v20
  OK   test constraint/angle/normal_roundtrip
  OK   test constraint/diameter/normal_migrate_from_v20
  OK   test constraint/symmetric/free_in_3d_roundtrip
  OK   test constraint/horizontal/pt_pt_roundtrip
  OK   test constraint/length_ratio/normal_roundtrip
  OK   test constraint/pt_line_distance/extended_render
  OK   test constraint/at_midpoint/line_pt_free_in_3d_migrate_from_v22
  OK   test constraint/angle/free_in_3d_roundtrip
  OK   test constraint/cubic_line_tangent/normal_migrate_from_v20
  OK   test constraint/points_coincident/normal_roundtrip
  OK   test constraint/at_midpoint/line_plane_normal_migrate_from_v22
  OK   test constraint/equal_line_arc_len/normal_roundtrip
  OK   test constraint/comment/normal_migrate_from_v20
  OK   test constraint/points_coincident/free_in_3d_roundtrip
  OK   test constraint/eq_pt_ln_distances/normal_migrate_from_v20
  OK   test core/path/is_absolute_unix
  OK   test constraint/proj_pt_distance/reference_migrate_from_v20
Generate::REGEN (for bounding box) took 46 ms
Generate::REGEN took 92 ms
Generate::ALL (for bounding box) took 46 ms
Generate::ALL took 161 ms
Generate::ALL (for bounding box) took 46 ms
Generate::ALL took 158 ms
  OK   test group/translate_nd/normal_roundtrip
  OK   test constraint/symmetric/normal_migrate_from_v20
  OK   test constraint/pt_in_plane/normal_migrate_from_v20
  OK   test constraint/equal_angle/other_migrate_from_v20
  OK   test constraint/curve_curve_tangent/arc_cubic_migrate_from_v20
  OK   test constraint/at_midpoint/line_plane_free_in_3d_migrate_from_v22
  OK   test constraint/proj_pt_distance/normal_migrate_from_v22
  OK   test request/cubic/normal_migrate_from_v20
  OK   test request/cubic/normal_roundtrip
  OK   test constraint/pt_on_line/free_in_3d_migrate_from_v22
  OK   test constraint/length_ratio/reference_roundtrip
  OK   test constraint/angle/reference_free_in_3d_migrate_from_v20
  OK   test constraint/equal_line_arc_len/normal_migrate_from_v22
  OK   test analysis/contour_area/normal_roundtrip
  OK   test constraint/diameter/normal_roundtrip
  OK   test request/cubic_periodic/normal_migrate_from_v20
  OK   test constraint/parallel/free_in_3d_roundtrip
  OK   test constraint/same_orientation/same_group_roundtrip
  OK   test constraint/same_orientation/normal_migrate_from_v20
  OK   test constraint/pt_plane_distance/normal_migrate_from_v20
  OK   test core/path/file_stem
  OK   test constraint/curve_curve_tangent/arc_cubic_migrate_from_v22
  OK   test constraint/pt_line_distance/normal_migrate_from_v20
  OK   test constraint/equal_line_arc_len/normal_migrate_from_v20
  OK   test constraint/vertical/pt_pt_roundtrip
  OK   test constraint/at_midpoint/line_pt_free_in_3d_migrate_from_v20
  OK   test constraint/angle/free_in_3d_migrate_from_v22
  OK   test group/translate_asy/normal_roundtrip
  OK   test constraint/horizontal/line_migrate_from_v20
  OK   test request/line_segment/normal_roundtrip
  OK   test constraint/pt_line_distance/free_in_3d_migrate_from_v22
  OK   test request/cubic/normal_migrate_from_v22
  OK   test core/expr/precedence
  OK   test constraint/pt_pt_distance/normal_roundtrip
  OK   test constraint/angle/normal_migrate_from_v22
  OK   test core/path/file_name
  OK   test core/path/from_portable
  OK   test constraint/angle/reference_free_in_3d_migrate_from_v22
  OK   test constraint/cubic_line_tangent/free_in_3d_migrate_from_v22
  OK   test constraint/points_coincident/free_in_3d_migrate_from_v20
  OK   test constraint/pt_on_face/normal_migrate_from_v22
  OK   test constraint/comment/normal_roundtrip
  OK   test group/link/normal_migrate_from_v20
  OK   test request/cubic_periodic/normal_migrate_from_v22
  OK   test constraint/length_ratio/reference_migrate_from_v20
  OK   test constraint/symmetric/free_in_3d_migrate_from_v20
  OK   test core/path/relative_to
  OK   test constraint/symmetric_vert/normal_roundtrip
  OK   test constraint/pt_on_line/right_free_in_3d_roundtrip
  OK   test core/path/parent
  OK   test constraint/symmetric_line/normal_migrate_from_v20
  OK   test constraint/pt_plane_distance/normal_migrate_from_v22
  OK   test constraint/symmetric_horiz/normal_migrate_from_v20
  OK   test constraint/at_midpoint/line_pt_free_in_3d_roundtrip
  OK   test constraint/cubic_line_tangent/free_in_3d_roundtrip
  OK   test core/expr/constant
  OK   test request/line_segment/normal_migrate_from_v20
  OK   test constraint/eq_pt_ln_distances/normal_roundtrip
  OK   test core/expr/binary_ops
  OK   test request/circle/normal_roundtrip
  OK   test constraint/diameter/reference_migrate_from_v22
  OK   test core/expr/parentheses
  OK   test request/circle/free_in_3d_dof
  OK   test constraint/cubic_line_tangent/normal_migrate_from_v22
  OK   test constraint/diameter/reference_roundtrip
  OK   test constraint/parallel/normal_roundtrip
  OK   test core/expr/variable
  OK   test request/datum_point/normal_roundtrip
  OK   test constraint/parallel/normal_migrate_from_v20
  OK   test group/link/normal_migrate_from_v22
  OK   test constraint/horizontal/line_roundtrip
  OK   test group/translate_asy/normal_inters
  OK   test constraint/arc_line_tangent/normal_roundtrip
  OK   test core/locale/parseable
Missing (empty) translation for group-name'#references'
Missing (empty) translation for group-name'sketch-in-plane'
  OK   test request/circle/free_in_3d_migrate_from_v22
  OK   test constraint/symmetric/normal_roundtrip
  OK   test constraint/eq_len_pt_line_d/normal_roundtrip
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
  OK   test constraint/pt_line_distance/normal_roundtrip
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
Vector::WithMagnitude(1) of zero vector!
test/constraint/pt_face_distance/test.cpp:21: FAILED: render doesn't match reference; 2 (0.00%) pixels differ
  NG   test constraint/pt_face_distance/reference_roundtrip
  OK   test constraint/symmetric_line/normal_migrate_from_v22
  OK   test constraint/arc_line_tangent/normal_migrate_from_v22
  OK   test constraint/proj_pt_distance/reference_roundtrip
  OK   test constraint/pt_pt_distance/reference_migrate_from_v20
  OK   test constraint/symmetric_vert/normal_migrate_from_v22
File ../test/harness.cpp, line 112, function PrepareSavefile:
Assertion failed: value.size() == newValue.size().
Message: Expected no change in value length.
Backtrace support not compiled in.
@nabijaczleweli
Copy link
Contributor Author

Working diff:

diff --git a/test/harness.cpp b/test/harness.cpp
index 6012425..6ec319c 100644
--- a/test/harness.cpp
+++ b/test/harness.cpp
@@ -107,7 +107,10 @@ static std::string PrepareSavefile(std::string data) {
                 if(SolveSpaceUI::SAVED[i].fmt  != 'f') continue;
                 if(SolveSpaceUI::SAVED[i].desc != key) continue;
                 double f = strtod(value.c_str(), NULL);
+                fprintf(stderr, "f=%s\n", value.c_str());
+                fprintf(stderr, "  f_pre =%.20f\n", f);
                 f = round(f * precision) / precision;
+                fprintf(stderr, "  f_post=%.20f\n", f);
                 std::string newValue = ssprintf("%.20f", f);
                 ssassert(value.size() == newValue.size(), "Expected no change in value length");
                 std::copy(newValue.begin(), newValue.end(),

Relevant value:

f=-9.99999999999999822364
  f_pre =-9.99999999999999822364
  f_post=-10.00000000000000000000
File ../test/harness.cpp, line 115, function PrepareSavefile:

Full log (833kB) (it's plaintext, but GH wouldn't accept other mimetypes sensibly)

@whitequark
Copy link
Contributor

I think this is because of x87 precision. I suggest simply not using i386, since there is no remaining reason to care about this architecture. But if you want it for some reason, you could try to find the changes to FP environment that bring it more in line with normal double precision floats.

@nabijaczleweli
Copy link
Contributor Author

Turns out passing -mfpmath=sse -msse2 to GCC does solve this; apologies for the clutter and thanks for the pointer!

@whitequark
Copy link
Contributor

We should probably enable that for GCC on i386 in the CMake scripts.

@ruevs
Copy link
Member

ruevs commented Mar 24, 2020

If we enable SSE then it is not i386 any more - (it does not have SSE :-).
However it should work if we use i387 (math coprocessor) floating point instructions. They are 80bit doubles and should work fine. I have no GCC machine with me right now to test but from this:

https://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/i386-and-x86-64-Options.html

It appears that we should use:

'-mfpmath=387'

(The reason it is not on by default is that on 80386 the 80387 coprocessor was a separate chip and not every PC had it).

@ruevs
Copy link
Member

ruevs commented Mar 24, 2020

@nabijaczleweli
Copy link
Contributor Author

According to this GCC doc, -mfpmath=387 is the default for 32-bit x86 targets (except Darwin, but previous versions of the document don't include that exception), and I've just confirmed this empirically.

Additionally, Clang seems to use SSE2 for floats when allowed to via -msse2 by default, but fails like GCC otherwise.

nabijaczleweli added a commit to nabijaczleweli/solvespace that referenced this issue Mar 24, 2020

Verified

This commit was signed with the committer’s verified signature.
Both GCC and Clang use x87 instructions by default on 32-bit x86
targets, but the loss of precision resulting from that has yielded
crashing tests (see referenced issue), and it can be safely assumed
there are very few CPUs that both don't support SSE2 and are expected to
run SolveSpace

This commit also removes a now-redundant check for 32-bit Windows
against TARGET, which doesn't seem to be actually set by CMake at all

Ref: solvespace#565
@ruevs
Copy link
Member

ruevs commented Mar 24, 2020

In this case I think whatever is failing is a bug (I'll take a look when I end up on a PC) and we should not hide it by using SSE.

@whitequark
Copy link
Contributor

whitequark commented Mar 24, 2020

If we enable SSE then it is not i386 any more - (it does not have SSE :-).

That's incorrect. While you can build software for a target called "i386", no Linux distribution released in the last several years, and indeed no such Linux kernel release, will run without SSE, much less on an actual i386. Some toolchains call the same target "i686", although that's not quite literally true either.

However it should work if we use i387 (math coprocessor) floating point instructions. They are 80bit doubles and should work fine.

Using nonstandard 80 bit floating point numbers is exactly the cause of the problem @nabijaczleweli is facing here. They're rounded differently than what the tests are expecting and so the test fixtures don't match.

I have no GCC machine with me right now to test but from this:

In the future, please make sure to test your speculation before making authoritative statements. I wrote all of these tests and know perfectly well why they break here.

In this case I think whatever is failing is a bug (I'll take a look when I end up on a PC) and we should not hide it by using SSE.

The "bug" here is that the testsuite effectively depend on specific rounding modes and floating point sizes. Although I would agree that a testsuite ideally should not depend on that, this was the best I could come up with. Of course, you are welcome to try and do a better job.

nabijaczleweli added a commit to nabijaczleweli/solvespace that referenced this issue Mar 24, 2020

Verified

This commit was signed with the committer’s verified signature.
Both GCC and Clang use x87 instructions by default on 32-bit x86
targets, but the loss of precision resulting from that has yielded
crashing tests (see referenced issue), and it can be safely assumed
there are very few CPUs that both don't support SSE2 and are expected to
run SolveSpace

This commit also removes a now-redundant check for 32-bit Windows
against TARGET, which doesn't seem to be actually set by CMake at all

Ref: solvespace#565
@ruevs
Copy link
Member

ruevs commented Mar 24, 2020

You are right.

@whitequark
Copy link
Contributor

Thanks.

whitequark pushed a commit that referenced this issue Mar 24, 2020
Both GCC and Clang use x87 instructions by default on 32-bit x86
targets, but the loss of precision resulting from that has yielded
crashing tests (see referenced issue), and it can be safely assumed
there are very few CPUs that both don't support SSE2 and are expected to
run SolveSpace

This commit also removes a now-redundant check for 32-bit Windows
against TARGET, which doesn't seem to be actually set by CMake at all

Ref: #565
devin-ai-integration bot pushed a commit to erkinalp/solvespace that referenced this issue Apr 3, 2025
Both GCC and Clang use x87 instructions by default on 32-bit x86
targets, but the loss of precision resulting from that has yielded
crashing tests (see referenced issue), and it can be safely assumed
there are very few CPUs that both don't support SSE2 and are expected to
run SolveSpace

This commit also removes a now-redundant check for 32-bit Windows
against TARGET, which doesn't seem to be actually set by CMake at all

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

No branches or pull requests

3 participants