1
- let run ~benchmarks ?(budgetf = 0.025 ) ?(filters = [] ) ?(debug = false )
1
+ let print_diff base next =
2
+ let open Data in
3
+ Option. pair (Results. parse base) (Results. parse next)
4
+ |> Option. iter @@ fun (base , next ) ->
5
+ List. zip_by Benchmark. compare_by_name base next
6
+ |> List. iter @@ fun ((base : Benchmark.t ), (next : Benchmark.t )) ->
7
+ Printf. printf " %s:\n " base.name;
8
+ List. zip_by Metric. compare_by_name base.metrics next.metrics
9
+ |> List. iter @@ fun ((base : Metric.t ), (next : Metric.t )) ->
10
+ Printf. printf " %s:\n " base.name;
11
+ if base.trend <> next.trend || base.units <> next.units then
12
+ Printf. printf " %.2f %s\n " next.value next.units
13
+ else
14
+ let times = next.value /. base.value in
15
+ if
16
+ (next.trend = `Higher_is_better && times < 0.95 )
17
+ || (next.trend = `Lower_is_better && 1.05 < times)
18
+ then
19
+ Printf. printf
20
+ " %.2f %s = \x1b [1;31m%.2f\x1b\x1b [0;39;49m x %.2f %s\n "
21
+ next.value next.units times base.value base.units
22
+ else if
23
+ (next.trend = `Higher_is_better && 1.05 < times)
24
+ || (next.trend = `Lower_is_better && times < 0.95 )
25
+ then
26
+ Printf. printf
27
+ " %.2f %s = \x1b [1;32m%.2f\x1b\x1b [0;39;49m x %.2f %s\n "
28
+ next.value next.units times base.value base.units
29
+ else
30
+ Printf. printf
31
+ " %.2f %s = \x1b [1;33m%.2f\x1b\x1b [0;39;49m x %.2f %s\n "
32
+ next.value next.units times base.value base.units
33
+
34
+ let run_benchmark ~budgetf ~debug (name , fn ) =
35
+ if debug then
36
+ (* I wish there was a way to tell dune not to capture stderr. *)
37
+ Printf. printf " Running: %s\n %!" name;
38
+ `Assoc [ (" name" , `String name); (" metrics" , `List (fn ~budgetf )) ]
39
+
40
+ let build_filter = function
41
+ | [] -> Fun. const true
42
+ | filters -> begin
43
+ let regexps = filters |> List. map Str. regexp in
44
+ fun (name , _ ) ->
45
+ regexps
46
+ |> List. exists @@ fun regexp ->
47
+ match Str. search_forward regexp name 0 with
48
+ | _ -> true
49
+ | exception Not_found -> false
50
+ end
51
+
52
+ let run ~benchmarks ?(budgetf = 0.025 ) ?(filters = [] ) ?(debug = false ) ?diff
2
53
?(argv = Sys. argv) ?(flush = true ) () =
3
54
let budgetf = ref budgetf in
4
55
let filters = ref filters in
5
56
let debug = ref debug in
57
+ let diff = ref diff in
6
58
7
59
let rec specs =
8
60
[
9
61
(" -budget" , Arg. Set_float budgetf, " seconds\t Budget for a benchmark" );
10
62
( " -debug" ,
11
63
Arg. Set debug,
12
64
" \t Print progress information to help debugging" );
65
+ ( " -diff" ,
66
+ Arg. String (fun path -> diff := Some path),
67
+ " path.json\t Show diff against specified base results" );
13
68
(" -help" , Unit help, " \t Show this help message" );
14
69
(" --help" , Unit help, " \t Show this help message" );
15
70
]
@@ -30,35 +85,24 @@ let run ~benchmarks ?(budgetf = 0.025) ?(filters = []) ?(debug = false)
30
85
in
31
86
Arg. parse_argv argv specs (fun filter -> filters := filter :: ! filters) " " ;
32
87
33
- let budgetf = ! budgetf in
34
-
35
- if budgetf < 0.0 || 60.0 *. 60.0 < budgetf then
88
+ if ! budgetf < 0.0 || 60.0 *. 60.0 < ! budgetf then
36
89
invalid_arg " budgetf out of range" ;
37
90
38
- let run (name , fn ) =
39
- if ! debug then
40
- (* I wish there was a way to tell dune not to capture stderr. *)
41
- Printf. printf " Running: %s\n %!" name;
42
- let metrics = fn ~budgetf in
43
- `Assoc [ (" name" , `String name); (" metrics" , `List metrics) ]
44
- in
45
-
46
- let filter =
47
- match ! filters with
48
- | [] -> Fun. const true
49
- | filters -> begin
50
- let regexps = filters |> List. map Str. regexp in
51
- fun (name , _ ) ->
52
- regexps
53
- |> List. exists @@ fun regexp ->
54
- match Str. search_forward regexp name 0 with
55
- | _ -> true
56
- | exception Not_found -> false
57
- end
91
+ let results =
92
+ `Assoc
93
+ [
94
+ ( " results" ,
95
+ `List
96
+ (benchmarks
97
+ |> List. filter (build_filter ! filters)
98
+ |> List. map (run_benchmark ~debug: ! debug ~budgetf: ! budgetf)) );
99
+ ]
58
100
in
59
101
60
- `Assoc
61
- [ (" results" , `List (benchmarks |> List. filter filter |> List. map run)) ]
62
- |> Yojson.Safe. pretty_print ~std: true Format. std_formatter;
102
+ begin
103
+ match ! diff with
104
+ | None -> Yojson.Safe. pretty_print ~std: true Format. std_formatter results
105
+ | Some fname -> print_diff (Yojson.Safe. from_file fname) results
106
+ end ;
63
107
64
108
if flush then Format. print_flush ()
0 commit comments