Skip to content

Commit 29eb834

Browse files
authored
Merge pull request #387 from ocaml-multicore/outchannel-shrink-cleanup
Lin Out_channel shrink cleanup
2 parents fcf90a5 + b9509bb commit 29eb834

File tree

4 files changed

+96
-55
lines changed

4 files changed

+96
-55
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Next
44

5+
- #387: Reduce needless allocations in `Lin`'s sequential consistency
6+
search, as part of an `Out_channel` test cleanup
57
- #379: Extend the set of `Util.Pp` pretty-printers and teach them to
68
add break hints similar to `ppx_deriving.show`; teach `to_show` to
79
generate truncated strings when `$MCTUTILS_TRUNCATE` environment

lib/lin.ml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ struct
4747
(* plain interpreter of a cmd list *)
4848
let interp_plain sut cs = List.map (fun c -> (c, Spec.run c sut)) cs
4949

50+
(* plain interpreter ignoring the output and allocating less *)
51+
let interp_plain_ignore sut cs = List.iter (fun c -> ignore (Spec.run c sut)) cs
52+
5053
let rec gen_cmds fuel =
5154
Gen.(if fuel = 0
5255
then return []
@@ -113,7 +116,7 @@ struct
113116
||
114117
(* rerun to get seq_sut to same cmd branching point *)
115118
(let seq_sut' = Spec.init () in
116-
let _ = interp_plain seq_sut' (List.rev seq_trace) in
119+
interp_plain_ignore seq_sut' (List.rev seq_trace);
117120
if Spec.equal_res res2 (Spec.run c2 seq_sut')
118121
then check_seq_cons pref cs1 cs2' seq_sut' (c2::seq_trace)
119122
else (Spec.cleanup seq_sut'; false))

src/io/lin_tests.ml

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -71,66 +71,90 @@ end
7171

7272
module Out_channel_ops = struct
7373

74-
type t = string * Out_channel.t (* Filename and corresponding channel *)
75-
76-
type cmd = Flush | Close | Write of string
74+
type t = Out_channel.t
75+
let path = ref ""
76+
77+
type cmd =
78+
| Seek of int64
79+
| Close
80+
| Flush
81+
| Output_string of string
82+
| Set_binary_mode of bool
83+
| Set_buffered of bool
84+
| Is_buffered
7785

7886
let show_cmd =
7987
let open Printf in function
80-
| Flush -> "Flush"
81-
| Write s -> sprintf "Write %s" s
88+
| Seek i -> sprintf "Seek %Li" i
8289
| Close -> "Close"
90+
| Flush -> "Flush"
91+
| Output_string s -> sprintf "Output_string %s" s
92+
| Set_binary_mode b -> sprintf "Set_binary_mode %s" QCheck.Print.(bool b)
93+
| Set_buffered b -> sprintf "Set_buffered %s" QCheck.Print.(bool b)
94+
| Is_buffered -> "Is_buffered"
8395

8496
let gen_cmd =
8597
let open QCheck.Gen in
8698
frequency
87-
[3, return Flush;
88-
1, return Close;
89-
6, map (fun s -> Write s) string;
99+
[10, map (fun i -> Seek (Int64.of_int i)) small_nat;
100+
10, return Close;
101+
10, return Flush;
102+
10, map (fun s -> Output_string s) string_small;
103+
10, map (fun b -> Set_binary_mode b) bool;
104+
10, map (fun b -> Set_buffered b) bool;
105+
10, return Is_buffered;
90106
]
91107

92108
let shrink_cmd _ = QCheck.Iter.empty
93109

94-
type res = (unit, exn) result
110+
type inner_res = Unit | Bool of bool
111+
type res = (inner_res, exn) result
95112

96113
let show_res =
97114
let open Printf in function
98-
| Ok () -> sprintf "()"
99-
| Error e -> sprintf "exception %s" (Printexc.to_string e)
115+
| Ok r -> (match r with
116+
| Unit -> sprintf "()"
117+
| Bool b -> QCheck.Print.(bool b)
118+
)
119+
| Error e -> sprintf "exception %s" (Printexc.to_string e)
100120

101121
let equal_res = (=)
102122

103123
let init () =
104-
let filename = Filename.temp_file "fuzz_stdlib" "" in
105-
filename, Out_channel.open_text filename
124+
let p,ch = Filename.open_temp_file "lin-dsl-" "" in
125+
path := p;
126+
ch
106127

107-
let cleanup (filename, chan) =
128+
let cleanup chan =
108129
Out_channel.close chan;
109-
try Sys.remove filename with Sys_error _ -> ()
130+
Sys.remove !path
110131

111-
let run cmd (_,chan) =
132+
let run cmd chan =
112133
match cmd with
113-
| Flush ->
114-
begin try Out_channel.flush chan; Ok ()
115-
with e -> Error e
116-
end
117-
| Write s ->
118-
begin try Out_channel.output_string chan s; Ok ()
119-
with e -> Error e
120-
end
134+
| Seek i ->
135+
(try Out_channel.seek chan i; Ok Unit with e -> Error e)
121136
| Close ->
122-
begin try Out_channel.close chan; Ok ()
123-
with e -> Error e
124-
end
137+
(try Out_channel.close chan; Ok Unit with e -> Error e)
138+
| Flush ->
139+
(try Out_channel.flush chan; Ok Unit with e -> Error e)
140+
| Output_string s ->
141+
(try Out_channel.output_string chan s; Ok Unit with e -> Error e)
142+
| Set_binary_mode b ->
143+
(try Out_channel.set_binary_mode chan b; Ok Unit with e -> Error e)
144+
| Set_buffered b ->
145+
(try Out_channel.set_buffered chan b; Ok Unit with e -> Error e)
146+
| Is_buffered ->
147+
(try Ok (Bool (Out_channel.is_buffered chan)) with e -> Error e)
148+
125149
end
126150

127-
module Out_channel_lin = Lin_domain.Make_internal (Out_channel_ops) [@@alert "-internal"]
128151
module In_channel_lin = Lin_domain.Make_internal (In_channel_ops) [@@alert "-internal"]
152+
module Out_channel_lin = Lin_domain.Make_internal (Out_channel_ops) [@@alert "-internal"]
129153

130154
let () =
131155
QCheck_base_runner.run_tests_main
132-
[ Out_channel_lin.lin_test ~count:1000 ~name:"Lin Out_channel test with domains";
133-
In_channel_lin.lin_test ~count:1000 ~name:"Lin In_channel test with domains";
156+
[ In_channel_lin.lin_test ~count:1000 ~name:"Lin In_channel test with domains";
157+
Out_channel_lin.lin_test ~count:1000 ~name:"Lin Out_channel test with domains";
134158
]
135159

136160
let () =

src/io/lin_tests_spec_io.ml

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -65,18 +65,30 @@ end
6565
module OCConf : Lin.Spec = struct
6666
(* a path and an open channel to that file; we need to keep the path
6767
to cleanup after the test run *)
68-
type t = string * Out_channel.t
68+
type t = Out_channel.t
69+
let path = ref ""
6970

70-
let init () = Filename.open_temp_file "lin-dsl-" ""
71-
let cleanup (path, chan) =
72-
Out_channel.close chan ;
73-
Sys.remove path
71+
let init () =
72+
let p,ch = Filename.open_temp_file "lin-dsl-" "" in
73+
path := p;
74+
ch
7475

75-
(* turn [f: Out_channel.t -> ...] into [lift f: t -> ...] *)
76-
let lift f (_, chan) = f chan
76+
let cleanup chan =
77+
Out_channel.close chan;
78+
Sys.remove !path
7779

7880
open Lin
79-
let int,int64,string,bytes = nat_small,nat64_small,string_small,bytes_small
81+
let int,int64 = nat_small,nat64_small
82+
83+
(* disable string and bytes char shrinking as too many shrinking candidates
84+
triggers long Out_channel shrink runs on Mingw + Cygwin *)
85+
let string =
86+
let string = QCheck.(set_shrink Shrink.(string ~shrink:nil) string_small) in
87+
gen_deconstructible string (print Lin.string) String.equal
88+
let bytes =
89+
let bytes = QCheck.(set_shrink Shrink.(bytes ~shrink:nil) bytes_small) in
90+
gen_deconstructible bytes (print Lin.bytes) Bytes.equal
91+
8092
let api = [
8193
(* Only one t is tested, so skip stdout, stderr and opening functions *)
8294

@@ -89,21 +101,21 @@ module OCConf : Lin.Spec = struct
89101
(* val_ "Out_channel.with_open_text" Out_channel.with_open_text (string @-> (t @-> 'a) @-> returning 'a) ; *)
90102
(* val_ "Out_channel.with_open_gen" Out_channel.with_open_gen (open_flag list @-> int @-> string @-> (t @-> 'a) @-> returning 'a) ; *)
91103

92-
val_ "Out_channel.seek" (lift Out_channel.seek) (t @-> int64 @-> returning_or_exc unit) ;
93-
val_freq 3 "Out_channel.pos" (lift Out_channel.pos) (t @-> returning_or_exc int64) ;
94-
val_freq 3 "Out_channel.length" (lift Out_channel.length) (t @-> returning_or_exc int64) ;
95-
val_ "Out_channel.close" (lift Out_channel.close) (t @-> returning_or_exc unit) ;
96-
val_ "Out_channel.close_noerr" (lift Out_channel.close_noerr) (t @-> returning unit) ;
97-
val_ "Out_channel.flush" (lift Out_channel.flush) (t @-> returning_or_exc unit) ;
98-
val_ "Out_channel.flush_all" Out_channel.flush_all (unit @-> returning_or_exc unit) ;
99-
val_ "Out_channel.output_char" (lift Out_channel.output_char) (t @-> char @-> returning_or_exc unit) ;
100-
val_ "Out_channel.output_byte" (lift Out_channel.output_byte) (t @-> int @-> returning_or_exc unit) ;
101-
val_ "Out_channel.output_string" (lift Out_channel.output_string) (t @-> string @-> returning_or_exc unit) ;
102-
val_ "Out_channel.output_bytes" (lift Out_channel.output_bytes) (t @-> bytes @-> returning_or_exc unit) ;
103-
val_ "Out_channel.output" (lift Out_channel.output) (t @-> bytes @-> int @-> int @-> returning_or_exc unit) ;
104-
val_ "Out_channel.output_substring" (lift Out_channel.output_substring) (t @-> string @-> int @-> int @-> returning_or_exc unit) ;
105-
val_ "Out_channel.set_binary_mode" (lift Out_channel.set_binary_mode) (t @-> bool @-> returning_or_exc unit) ;
106-
val_ "Out_channel.set_buffered" (lift Out_channel.set_buffered) (t @-> bool @-> returning_or_exc unit) ;
107-
val_ "Out_channel.is_buffered" (lift Out_channel.is_buffered) (t @-> returning_or_exc bool) ;
104+
val_freq 10 "Out_channel.seek" Out_channel.seek (t @-> int64 @-> returning_or_exc unit) ;
105+
val_freq 20 "Out_channel.pos" Out_channel.pos (t @-> returning_or_exc int64) ;
106+
val_freq 20 "Out_channel.length" Out_channel.length (t @-> returning_or_exc int64) ;
107+
val_freq 10 "Out_channel.close" Out_channel.close (t @-> returning_or_exc unit) ;
108+
val_freq 10 "Out_channel.close_noerr" Out_channel.close_noerr (t @-> returning unit) ;
109+
val_freq 10 "Out_channel.flush" Out_channel.flush (t @-> returning_or_exc unit) ;
110+
(*val_freq 1 "Out_channel.flush_all" Out_channel.flush_all (unit @-> returning_or_exc unit) ;*)
111+
val_freq 10 "Out_channel.output_char" Out_channel.output_char (t @-> char @-> returning_or_exc unit) ;
112+
val_freq 10 "Out_channel.output_byte" Out_channel.output_byte (t @-> int @-> returning_or_exc unit) ;
113+
val_freq 10 "Out_channel.output_string" Out_channel.output_string (t @-> string @-> returning_or_exc unit) ;
114+
val_freq 10 "Out_channel.output_bytes" Out_channel.output_bytes (t @-> bytes @-> returning_or_exc unit) ;
115+
val_freq 10 "Out_channel.output" Out_channel.output (t @-> bytes @-> int @-> int @-> returning_or_exc unit) ;
116+
val_freq 10 "Out_channel.output_substring" Out_channel.output_substring (t @-> string @-> int @-> int @-> returning_or_exc unit) ;
117+
val_freq 10 "Out_channel.set_binary_mode" Out_channel.set_binary_mode (t @-> bool @-> returning_or_exc unit) ;
118+
val_freq 10 "Out_channel.set_buffered" Out_channel.set_buffered (t @-> bool @-> returning_or_exc unit) ;
119+
val_freq 10 "Out_channel.is_buffered" Out_channel.is_buffered (t @-> returning_or_exc bool) ;
108120
]
109121
end

0 commit comments

Comments
 (0)