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

Add IO tests #270

Merged
merged 7 commits into from
Jan 25, 2023
Merged

Add IO tests #270

merged 7 commits into from
Jan 25, 2023

Conversation

shym
Copy link
Collaborator

@shym shym commented Dec 14, 2022

Add tests for In_channel and Out_channel.
Rebase and fix @OlivierNicole’s Lin tests (#13). Add tests using the Lin DSL.

@shym
Copy link
Collaborator Author

shym commented Dec 14, 2022

These tests take quite some time, in particular Lin_thread ones, as we would expect. They didn’t trigger any crash in repeated runs (1, 2).
I wonder about exceptions appearing in log: should they not be caught up?

Anyway, should these tests be disabled in standard runs?

@shym
Copy link
Collaborator Author

shym commented Dec 19, 2022

I’m not sure I understand the issue in that run
https://github.com/shym/multicoretests/actions/runs/3732837838/jobs/6332819522#step:10:406
but so I added exceptions as possible results for Out_channel.close.

@jmid
Copy link
Collaborator

jmid commented Dec 19, 2022

Modulo the failing trunk workflows (and me messing up the debug label) this is starting to turn green.

I was just looking at the log and spotted this gem from macOS 5.0.0:
https://github.com/ocaml-multicore/multicoretests/actions/runs/3733518141/jobs/6334412511#step:10:567

random seed: 173862660
generated error fail pass / total     time test name

[ ]    0    0    0    0 / 1000     0.0s Lin DSL In_channel test with Domain
[ ]    0    0    0    0 / 1000     0.0s Lin DSL In_channel test with Domain (generating)
[✓]   10    0    1    9 / 1000    23.8s Lin DSL In_channel test with Domain

[ ]    0    0    0    0 / 1000     0.0s Lin DSL Out_channel test with Domain
[ ]   38    0    0   38 / 1000    37.1s Lin DSL Out_channel test with Domain
[ ]   57    0    0   57 / 1000   181.9s Lin DSL Out_channel test with Domain
[ ]   70    0    0   70 / 1000   524.2s Lin DSL Out_channel test with Domain
[ ]  104    0    0  104 / 1000   584.7s Lin DSL Out_channel test with Domain
[ ]  112    0    0  112 / 1000   644.9s Lin DSL Out_channel test with Domain (shrinking:   26.0018)
[ ]  112    0    0  112 / 1000   705.0s Lin DSL Out_channel test with Domain (shrinking:   36.0052)
[ ]  112    0    0  112 / 1000   765.0s Lin DSL Out_channel test with Domain (shrinking:   47.0005)
[ ]  112    0    0  112 / 1000   825.1s Lin DSL Out_channel test with Domain (shrinking:   61.0009)
[ ]  112    0    0  112 / 1000   885.2s Lin DSL Out_channel test with Domain (shrinking:   73.0011)
[ ]  112    0    0  112 / 1000   945.2s Lin DSL Out_channel test with Domain (shrinking:   87.0015)
[ ]  112    0    0  112 / 1000  1005.4s Lin DSL Out_channel test with Domain (shrinking:  106.0014)
[ ]  112    0    0  112 / 1000  1065.6s Lin DSL Out_channel test with Domain (shrinking:  126.0007)
[ ]  112    0    0  112 / 1000  1125.6s Lin DSL Out_channel test with Domain (shrinking:  145.0013)
[ ]  112    0    0  112 / 1000  1185.7s Lin DSL Out_channel test with Domain (shrinking:  159.0003)
[ ]  112    0    0  112 / 1000  1246.1s Lin DSL Out_channel test with Domain (shrinking:  168.0015)
[ ]  112    0    0  112 / 1000  1306.3s Lin DSL Out_channel test with Domain (shrinking:  179.0005)
[ ]  112    0    0  112 / 1000  1366.3s Lin DSL Out_channel test with Domain (shrinking:  188.0013)
[ ]  112    0    0  112 / 1000  1426.6s Lin DSL Out_channel test with Domain (shrinking:  198.0006)
[ ]  112    0    0  112 / 1000  1486.7s Lin DSL Out_channel test with Domain (shrinking:  213.0005)
[ ]  112    0    0  112 / 1000  1546.9s Lin DSL Out_channel test with Domain (shrinking:  228.0002)
[ ]  112    0    0  112 / 1000  1607.0s Lin DSL Out_channel test with Domain (shrinking:  244.0003)
[ ]  112    0    0  112 / 1000  1667.0s Lin DSL Out_channel test with Domain (shrinking:  255.0007)
[ ]  112    0    0  112 / 1000  1727.1s Lin DSL Out_channel test with Domain (shrinking:  269.0011)
[ ]  112    0    0  112 / 1000  1787.2s Lin DSL Out_channel test with Domain (shrinking:  280)
[ ]  112    0    0  112 / 1000  1847.3s Lin DSL Out_channel test with Domain (shrinking:  291.0018)
[ ]  112    0    0  112 / 1000  1907.6s Lin DSL Out_channel test with Domain (shrinking:  302.0018)
[ ]  112    0    0  112 / 1000  1968.2s Lin DSL Out_channel test with Domain (shrinking:  316.0006)
[ ]  112    0    0  112 / 1000  2028.3s Lin DSL Out_channel test with Domain (shrinking:  330.0011)
[✓]  113    0    1  112 / 1000  2054.8s Lin DSL Out_channel test with Domain

--- Info -----------------------------------------------------------------------

Negative test Lin DSL In_channel test with Domain failed as expected (42 shrink steps):

                                            |                 
                                   In_channel.seek t 4        
                                 In_channel.close_noerr t     
                                   In_channel.seek t 0        
                                 In_channel.input_byte t      
                            In_channel.set_binary_mode t false
                                   In_channel.seek t 72       
                                            |                 
                          .-----------------------------------.
                          |                                   |                 


+++ Messages ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Messages for test Lin DSL In_channel test with Domain:

  Results incompatible with sequential execution

                                                                     |                               
                                                       In_channel.seek t 4 : Ok (())                 
                                                       In_channel.close_noerr t : ()                 
                                                       In_channel.seek t 0 : Ok (())                 
                                                  In_channel.input_byte t : Ok (Some (0))            
                                               In_channel.set_binary_mode t false : Ok (())          
                                      In_channel.seek t 72 : Error (Sys_error("Bad file descriptor"))
                                                                     |                               
                                    .----------------------------------------------------------------.
                                    |                                                                | 

A sequential execution - which fails with Sys_error("Bad file descriptor") and hence isn't compatible with a ... sequential execution? Could this be because closing an in_channel invalidates it at some non-deterministic time in the future? 🤔

@shym
Copy link
Collaborator Author

shym commented Dec 21, 2022

The runtime code that closes a channel (here) doesn’t seem to leave the place for such non-determinism: the descriptor is invalidated while holding the channel lock.
Interestingly, seek can make input_byte succeed by marking old buffer content as valid again, even though close_noerr tried to mark it as invalidated (to ensure further input* on that channel would trigger an exception).
Well, anyway, it clearly doesn’t explain how this could behave differently between sequential and ... sequential runs.

@shym
Copy link
Collaborator Author

shym commented Dec 21, 2022

After reading the code again, in those circumstances, I think the content of the internal buffer that’s returned when doing the input is not always initialised, which could explain it could vary from one run to another? 🤔
Even if we’re reading from allocated memory (there should be no risk of a big crash there), it should be considered an OCaml bug?

Simple test:

let _ =
  let f = open_in Sys.argv.(0) in
  seek_in f 4 ;
  close_in_noerr f ;
  seek_in f 0 ;
  Printf.printf "Read: %d\n%!" (input_byte f) ;
  Printf.printf "Read: %d\n%!" (input_byte f) ;
  Printf.printf "Read: %d\n%!" (input_byte f) ;
  Printf.printf "Read: %d\n%!" (input_byte f) ;
  Printf.printf "Read: %d\n%!" (input_byte f)

gives:

$ ocamlopt bob.ml -o bob ; ./bob
Read: 0
Read: 0
Read: 0
Read: 0
Fatal error: exception Sys_error("Bad file descriptor")

@shym
Copy link
Collaborator Author

shym commented Jan 9, 2023

The bug encountered by this strange run was reported in ocaml/ocaml#11878.

@jmid
Copy link
Collaborator

jmid commented Jan 24, 2023

Should we rebase this to have a clean CI run? (the previous one had several unrelated CI failures adding noise)

@jmid
Copy link
Collaborator

jmid commented Jan 25, 2023

This looks all green, modulo a threadomain Windows crash.
Also, the timings to run these look reasonable to me.
OK to merge @shym?

@shym
Copy link
Collaborator Author

shym commented Jan 25, 2023

Let’s!

@jmid jmid merged commit 01300b7 into ocaml-multicore:main Jan 25, 2023
@shym shym deleted the io2 branch January 25, 2023 12:54
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

Successfully merging this pull request may close these issues.

None yet

3 participants