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

Possible regression, tests failing on mips and arm #597

Open
ii8 opened this issue Dec 31, 2024 · 6 comments
Open

Possible regression, tests failing on mips and arm #597

ii8 opened this issue Dec 31, 2024 · 6 comments

Comments

@ii8
Copy link
Contributor

ii8 commented Dec 31, 2024

Both mips and arm builds with glibc have the mlton.share and real tests failing:

https://github.com/ii8/mlton-builds/actions/runs/12553286520

testing mlton.share
MLton 20241230.203305-gb15e2d2 starting
   Compile SML starting
   Compile SML finished in 10.19 + 1.69 (14% GC)
   Compile and Assemble starting
      mips-linux-gnu-gcc -c \
          -I/home/runner/work/mlton-builds/mlton-builds/mlton/build/lib/mlton/targets/self/include \
          -std=gnu11 -fno-common -O1 -fno-strict-aliasing \
          -foptimize-sibling-calls -w \
          -I/home/runner/work/mlton-builds/mlton-builds/mlton/build/lib/mlton/include \
          -I/usr/local/mips-linux-gnu/include -o /tmp/fileEW9h6W.o \
          /tmp/filePxuATe.1.c
      mips-linux-gnu-gcc -c \
          -I/home/runner/work/mlton-builds/mlton-builds/mlton/build/lib/mlton/targets/self/include \
          -std=gnu11 -fno-common -O1 -fno-strict-aliasing \
          -foptimize-sibling-calls -w \
          -I/home/runner/work/mlton-builds/mlton-builds/mlton/build/lib/mlton/include \
          -I/usr/local/mips-linux-gnu/include -o /tmp/fileGj68Fa.o \
          /tmp/file4Fl7jN.0.c
   Compile and Assemble finished in 0.60 + 0.00 (0% GC)
   Link starting
      mips-linux-gnu-gcc -o mlton.share /tmp/fileEW9h6W.o /tmp/fileGj68Fa.o \
          -L/home/runner/work/mlton-builds/mlton-builds/mlton/build/lib/mlton/targets/self \
          -lmlton -lgdtoa -lm -lgmp -Wl,-znoexecstack \
          -L/usr/local/mips-linux-gnu/lib -static
   Link finished in 0.09 + 0.00 (0% GC)
MLton 20241230.203305-gb15e2d2 finished in 10.88 + 1.69 (13% GC)
304c304
< size of a is 464
---
> size of a is 480
mlton.share: difference with -type-check true -verbose 1 -cc mips-linux-gnu-gcc -cc-opt -I/usr/local/mips-linux-gnu/include -link-opt -L/usr/local/mips-linux-gnu/lib -link-opt -static 
testing real
MLton 20241230.203305-gb15e2d2 starting
   Compile SML starting
   Compile SML finished in 27.02 + 3.50 (11% GC)
   Compile and Assemble starting
      mips-linux-gnu-gcc -c \
          -I/home/runner/work/mlton-builds/mlton-builds/mlton/build/lib/mlton/targets/self/include \
          -std=gnu11 -fno-common -O1 -fno-strict-aliasing \
          -foptimize-sibling-calls -w \
          -I/home/runner/work/mlton-builds/mlton-builds/mlton/build/lib/mlton/include \
          -I/usr/local/mips-linux-gnu/include -o /tmp/fileVAz4tg.o \
          /tmp/fileqw8Not.2.c
      mips-linux-gnu-gcc -c \
          -I/home/runner/work/mlton-builds/mlton-builds/mlton/build/lib/mlton/targets/self/include \
          -std=gnu11 -fno-common -O1 -fno-strict-aliasing \
          -foptimize-sibling-calls -w \
          -I/home/runner/work/mlton-builds/mlton-builds/mlton/build/lib/mlton/include \
          -I/usr/local/mips-linux-gnu/include -o /tmp/fileC25V56.o \
          /tmp/fileKDAc6u.1.c
      mips-linux-gnu-gcc -c \
          -I/home/runner/work/mlton-builds/mlton-builds/mlton/build/lib/mlton/targets/self/include \
          -std=gnu11 -fno-common -O1 -fno-strict-aliasing \
          -foptimize-sibling-calls -w \
          -I/home/runner/work/mlton-builds/mlton-builds/mlton/build/lib/mlton/include \
          -I/usr/local/mips-linux-gnu/include -o /tmp/file3wvZ0K.o \
          /tmp/fileAf2pkB.0.c
   Compile and Assemble finished in 3.62 + 0.00 (0% GC)
   Link starting
      mips-linux-gnu-gcc -o real /tmp/fileVAz4tg.o /tmp/fileC25V56.o \
          /tmp/file3wvZ0K.o \
          -L/home/runner/work/mlton-builds/mlton-builds/mlton/build/lib/mlton/targets/self \
          -lmlton -lgdtoa -lm -lgmp -Wl,-znoexecstack \
          -L/usr/local/mips-linux-gnu/lib -static
   Link finished in 0.09 + 0.00 (0% GC)
MLton 20241230.203305-gb15e2d2 finished in 30.74 + 3.50 (10% GC)
6133c6133
< cos (0.123E1) = 0.3342376947
---
> cos (0.123E1) = 0.3342377245
6302c6302
< cos (~0.123E1) = 0.3342376947
---
> cos (~0.123E1) = 0.3342377245
real: difference with -type-check true -verbose 1 -cc mips-linux-gnu-gcc -cc-opt -I/usr/local/mips-linux-gnu/include -link-opt -L/usr/local/mips-linux-gnu/lib -link-opt -static 
@MatthewFluet
Copy link
Member

The differences with real are due to the fact that IEEE-754 only specifies correct rounding for basic arithmetic and different platforms (hardware and/or libm) can differ with respect to low-order bits on other operations (especially the trig operations). I'm not sure how accurately QEMU is trying to emulate the floating-point behavior of other hardware platforms. In any case, the real regression is explicitly whitelisted (https://github.com/MLton/mlton/blob/on-20241230-release/regression/whitelist), so shouldn't cause the regression script to exit with a non-zero code.

The differences with mlton.share are less clear. That regression test is checking that the MLton.share function, which maximizes sharing among heap objects reachable from the argument, is working as expected. There are a number of different expected outputs, depending on the object pointer size and alignment of the platform, though those are detected automatically from the (implicit) MLB variables. The expected output of 464 (bytes) corresponds to 32-bit pointers with 8-byte alignment, which seems likely for these platforms. But the actual output of 480 (bytes) doesn't correspond to any other combination (and all of the other sizes in the output are correct for rep32a4); it is exactly 16 bytes larger than expected. It is curious that both of those architectures exhibit the same difference. The sharing ought to be platform independent. That particular size of a is ... is reporting the post-sharing size of an (int * int) option array; the array has length 100, so the overhead isn't proportional to the number of elements.

@MatthewFluet
Copy link
Member

I'm really not sure about what might be happening with the mlton.share regression. Here is the code to initialize the array whose size is being computed before and after calling MLton.share a:

val one = 1 + length (CommandLine.arguments ())
val v = SOME (one, one)
val a = Array.tabulate (100, fn i =>
                        if i mod 2 = 0
                           then v
                        else SOME (i mod 3, i mod 3))
val () = Array.update (a, 0, NONE)

Before calling MLton.share a, the calculated size is 1232 bytes, which can be calculated as follows:

1232 = (12 + 4*100 + 4) + (4+4+4+4) + 50*(4+4+4+4)

  • 12 bytes for an array header

  • 4 bytes per array element * 100 array elements (each element is pointer sized)

  • 4 bytes padding at the end of the array (so that the next object is 8-byte aligned)

  • the first array element is NONE (represented by 0wx1) and the remaining 49 array elements at even indices are v, which is represented by a pointer to a common (int * int) object, whose size is:

    • 4 bytes for a normal object header
    • 4 bytes for an int (32-bit integer)
    • 4 bytes for an int (32-bit integer)
    • 4 bytes padding at the end of the object (so that the next object is 8-bytes aligned)
  • 50 array elements at odd indices are SOME (i mod 3, i mod 3), which are represented by pointers to distinct (int * int) objects, each of whose size is 16 bytes (as above)

After calling MLton.share a, all of the (0, 0), (1, 1), and (2, 2) objects are shared, so, rather than 50 distinct (int * int) objects (in addition to the (1, 1) object), there are just two (0, 0) and (2, 2) objects; the calculated size should be 464:

464 = (12 + 4*100 + 4) + (4+4+4+4) + (4+4+4+4) + (4+4+4+4)

The anomalous size of 480 seems as though there is one extra (int * int) object. If, somehow, length (CommandLine.arguments ()) were greater than 2, then the common object in v would be distinct from all of those in the odd indices, which could lead to an additional 16 bytes. But, the command-line regression test has no errors and it doesn't seem as though ./bin/regression could possibly pass additional arguments to the test program.

@ii8
Copy link
Contributor Author

ii8 commented Jan 1, 2025

I had a suspicion that this has to do with a peculiarity of glibc because it doesn't happen with musl. So I ran this on the newer ubuntu with a newer version of glibc: https://github.com/ii8/mlton-builds/actions/runs/12569906903

Now the test passes. Unfortunately on this version qemu is bugged for mips.

So I'm guessing the only part of that test program that calls into libc is CommandLine.arguments ()?

@MatthewFluet
Copy link
Member

So I'm guessing the only part of that test program that calls into libc is CommandLine.arguments ()?

The mlton.share regression test? No, there will certainly be other calls into libc, like for printing output (which includes both the actual printing and detecting whether stdout is a tty or file, to determine buffering style).

@ii8
Copy link
Contributor Author

ii8 commented Jan 1, 2025

Ah yes but those things shouldn't affect the result in any way right

@MatthewFluet
Copy link
Member

No, I wouldn't think so. But, then again, we don't really understand why the regression test was failing before. The CommandLine.arguments () was a conjecture, but doesn't really fit with the command-line regression test succeeding without errors.

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

No branches or pull requests

2 participants