1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
open Core
open Core_bench_internals
let stabilize_gc () =
let rec loop failsafe last_heap_live_words =
if failsafe <= 0
then failwith "unable to stabilize the number of live words in the major heap";
Gc.compact ();
let stat = Gc.stat () in
if stat.Gc.Stat.live_words <> last_heap_live_words
then loop (failsafe - 1) stat.Gc.Stat.live_words
in
loop 10 0
;;
let measure =
let module RC = Run_config in
let module M = Measurement_sample in
fun run_config test ->
let (Test.Basic_test.T f) = test.Test.Basic_test.f in
let f = f `init in
let max_samples = 3_000 in
let results = Array.init max_samples ~f:(fun _ -> M.create ()) in
let index = ref 0 in
let runs = ref 0 in
let total_runs = ref 0 in
let old_gc = Gc.get () in
let init_t1 = Time_float.now () in
let quota = RC.quota run_config in
let quota_max_count = Quota.max_count quota in
while
(not (Quota.fulfilled quota ~start:init_t1 ~num_calls:!total_runs))
&& !index < Array.length results
do
let current_runs = !runs in
let current_index = !index in
if RC.stabilize_gc_between_runs run_config || current_runs = 0 then stabilize_gc ();
if RC.no_compactions run_config
then Gc.set { (Gc.get ()) with Gc.Control.max_overhead = 1_000_000 };
let gc1 = Gc.quick_stat () in
let t1 = Time_float.now () in
for _ = 1 to current_runs do
ignore (f () : _)
done;
let t2 = Time_float.now () in
let gc2 = Gc.quick_stat () in
total_runs := !total_runs + current_runs;
Gc.set old_gc;
let s = results.(current_index) in
s.M.runs <- current_runs;
s.M.cycles <- Int63.zero;
s.M.nanos
<- Float.int63_round_down_exn (Time_float.Span.to_ns (Time_float.diff t2 t1));
s.M.minor_allocated
<- Float.iround_towards_zero_exn
(gc2.Gc.Stat.minor_words -. gc1.Gc.Stat.minor_words);
s.M.major_allocated
<- Float.iround_towards_zero_exn
(gc2.Gc.Stat.major_words -. gc1.Gc.Stat.major_words);
s.M.promoted
<- Float.iround_towards_zero_exn
(gc2.Gc.Stat.promoted_words -. gc1.Gc.Stat.promoted_words);
s.M.compactions <- gc2.Gc.Stat.compactions - gc1.Gc.Stat.compactions;
s.M.major_collections
<- gc2.Gc.Stat.major_collections - gc1.Gc.Stat.major_collections;
s.M.minor_collections
<- gc2.Gc.Stat.minor_collections - gc1.Gc.Stat.minor_collections;
incr index;
let next =
match RC.sampling_type run_config with
| `Linear k -> current_runs + k
| `Geometric scale ->
let next_geometric =
Float.iround_towards_zero_exn (Float.of_int current_runs *. scale)
in
Int.max next_geometric (current_runs + 1)
in
let next = Int.min next (quota_max_count - !total_runs) in
assert (next >= 0);
runs := next
done;
let end_time = Time_float.now () in
let total_samples = !index in
let largest_run = !runs in
let measurement =
Measurement.create
~name:(Test.Basic_test.name test)
~test_name:(Test.Basic_test.test_name test)
~file_name:(Test.Basic_test.file_name test)
~module_name:(Test.Basic_test.module_name test)
~largest_run
~sample_count:total_samples
~samples:results
in
Verbosity.print_high
"%s: Total time taken %s (%d samples, max runs %d).\n%!"
(Test.Basic_test.name test)
(Time_float.Span.to_string (Time_float.diff end_time init_t1))
total_samples
largest_run;
measurement
;;
let measure_all run_config tests =
Random.self_init ();
let module RC = Run_config in
Verbosity.set_verbosity (RC.verbosity run_config);
(match RC.quota run_config with
| Num_calls trials ->
Verbosity.print_low
"Estimated testing time unknown (%d benchmarks x %d trials). Change using '-quota'.\n\
%!"
(List.length tests)
trials
| Span span ->
let est_time = Time_float.Span.scale span (Float.of_int (List.length tests)) in
Verbosity.print_low
"Estimated testing time %s (%d benchmarks x %s). Change using '-quota'.\n%!"
(Time_float.Span.to_string est_time)
(List.length tests)
(Time_float.Span.to_string span));
List.map tests ~f:(measure run_config)
;;