11module Times = struct
2- type t = { inverted : bool ; times : float array }
2+ type t = { inverted : bool ; times : float array ; runs : int }
33
4- let record ~n_domains ?(n_warmups = 3 ) ?(n_runs = 17 ) ?(before = Fun. id) ~init
5- ~work ?(after = Fun. id) () =
4+ let record ~n_domains ~budgetf ?(n_warmups = 3 ) ?(n_runs_min = 7 )
5+ ?(before = Fun. id) ~init ~work ?(after = Fun. id) () =
6+ let barrier_init = Barrier. make n_domains in
67 let barrier_before = Barrier. make n_domains in
78 let barrier_after = Barrier. make n_domains in
8- let results = Array. init n_domains @@ fun _ -> Stack. create () in
9+ let results =
10+ Array. init n_domains @@ fun _ ->
11+ Stack. create () |> Multicore_magic. copy_as_padded
12+ in
13+ let budget_used = ref false |> Multicore_magic. copy_as_padded in
14+ let runs = ref 0 |> Multicore_magic. copy_as_padded in
15+ Gc. full_major () ;
16+ let budget_start = Mtime_clock. elapsed () in
917 let main domain_i =
1018 for _ = 1 to n_warmups do
11- if domain_i = 0 then before () ;
19+ if domain_i = 0 then begin
20+ before () ;
21+ Gc. major ()
22+ end ;
1223 let state = init domain_i in
1324 Barrier. await barrier_before;
1425 work domain_i state;
1526 Barrier. await barrier_after;
1627 if domain_i = 0 then after ()
1728 done ;
18- for _run_i = 0 to n_runs - 1 do
19- if domain_i = 0 then before () ;
29+ while ! runs < n_runs_min || not ! budget_used do
30+ Barrier. await barrier_init;
31+ if domain_i = 0 then begin
32+ before () ;
33+ if
34+ let budget_stop = Mtime_clock. elapsed () in
35+ let elapsedf =
36+ Mtime.Span. to_float_ns
37+ (Mtime.Span. abs_diff budget_stop budget_start)
38+ *. (1. /. 1_000_000_000.0 )
39+ in
40+ budgetf < elapsedf
41+ then budget_used := true ;
42+ incr runs;
43+ Gc. major ()
44+ end ;
2045 let state = init domain_i in
2146 Barrier. await barrier_before;
2247 let start = Mtime_clock. elapsed () in
@@ -69,21 +94,32 @@ module Times = struct
6994 times.(run_i) < - times.(run_i) +. Stack. pop results.(domain_i)
7095 done
7196 done ;
72- { inverted = false ; times }
97+ { inverted = false ; times; runs = ! runs }
7398
74- let invert t =
75- { inverted = not t.inverted; times = Array. map (fun v -> 1.0 /. v) t.times }
99+ let invert { inverted; times; runs } =
100+ {
101+ inverted = not inverted;
102+ times = Array. map (fun v -> 1.0 /. v) times;
103+ runs;
104+ }
76105end
77106
78107module Stats = struct
79- type t = { mean : float ; median : float ; sd : float ; inverted : bool }
108+ type t = {
109+ mean : float ;
110+ median : float ;
111+ sd : float ;
112+ inverted : bool ;
113+ runs : int ;
114+ }
80115
81- let scale factor t =
116+ let scale factor { mean; median; sd; inverted; runs } =
82117 {
83- mean = t.mean *. factor;
84- median = t.median *. factor;
85- sd = t.sd *. factor;
86- inverted = t.inverted;
118+ mean = mean *. factor;
119+ median = median *. factor;
120+ sd = sd *. factor;
121+ inverted;
122+ runs;
87123 }
88124
89125 let mean_of times =
@@ -99,11 +135,11 @@ module Stats = struct
99135 if n land 1 = 0 then (times.((n asr 1 ) - 1 ) +. times.(n asr 1 )) /. 2.0
100136 else times.(n asr 1 )
101137
102- let of_times ( t : Times.t ) =
103- let mean = mean_of t. times in
104- let sd = sd_of t. times mean in
105- let median = median_of t. times in
106- { mean; sd; median; inverted = t.inverted }
138+ let of_times Times. { inverted; times; runs } =
139+ let mean = mean_of times in
140+ let sd = sd_of times mean in
141+ let median = median_of times in
142+ { mean; sd; median; inverted; runs }
107143
108144 let to_nonbreaking s =
109145 s |> String. split_on_char ' '
@@ -120,6 +156,7 @@ module Stats = struct
120156 if t.inverted then `String " higher-is-better"
121157 else `String " lower-is-better" );
122158 (" description" , `String description);
159+ (" #runs" , `Int t.runs);
123160 ]
124161 in
125162 [ metric t.median ]
0 commit comments