Skip to content

Commit f639e06

Browse files
committed
xstringext: Add benchmark for escaped
Signed-off-by: Christian Pardillo Laursen <christian.pardillolaursen@citrix.com>
1 parent ab74a67 commit f639e06

File tree

2 files changed

+136
-0
lines changed

2 files changed

+136
-0
lines changed
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
open Bechamel
2+
open Toolkit
3+
module XString = Xapi_stdext_std.Xstringext.String
4+
5+
(* Test data generators *)
6+
let make_string len = String.init len (fun i -> Char.chr (33 + (i mod 94)))
7+
8+
let escape_rules =
9+
[('a', "[A]"); ('e', "[E]"); ('i', "[I]"); ('o', "[O]"); ('u', "[U]")]
10+
11+
(* Reference implementation from xstringext_test.ml *)
12+
let escaped_spec ?rules string =
13+
match rules with
14+
| None ->
15+
String.escaped string
16+
| Some rules ->
17+
let apply_rules char =
18+
match List.assoc_opt char rules with
19+
| None ->
20+
Seq.return char
21+
| Some replacement ->
22+
String.to_seq replacement
23+
in
24+
string |> String.to_seq |> Seq.concat_map apply_rules |> String.of_seq
25+
26+
let escaped_benchmark n =
27+
let s = make_string n in
28+
Staged.stage @@ fun () -> ignore (XString.escaped ~rules:escape_rules s)
29+
30+
let escaped_spec_benchmark n =
31+
let s = make_string n in
32+
Staged.stage @@ fun () -> ignore (escaped_spec ~rules:escape_rules s)
33+
34+
let test_escaped =
35+
Test.make_indexed ~name:"escaped" ~fmt:"%s %d" ~args:[100; 500; 1000]
36+
escaped_benchmark
37+
38+
let test_escaped_spec =
39+
Test.make_indexed ~name:"escaped-spec" ~fmt:"%s %d" ~args:[100; 500; 1000]
40+
escaped_spec_benchmark
41+
42+
let benchmark () =
43+
let ols =
44+
Analyze.ols ~bootstrap:0 ~r_square:true ~predictors:Measure.[|run|]
45+
in
46+
let instances =
47+
Instance.[minor_allocated; major_allocated; monotonic_clock]
48+
in
49+
let cfg =
50+
Benchmark.cfg ~limit:2000 ~quota:(Time.second 0.5) ~kde:(Some 1000) ()
51+
in
52+
let test =
53+
Test.make_grouped ~name:"escaped-comparison"
54+
[test_escaped; test_escaped_spec]
55+
in
56+
let raw_results = Benchmark.all cfg instances test in
57+
let results =
58+
List.map (fun instance -> Analyze.all ols instance raw_results) instances
59+
in
60+
let results = Analyze.merge ols instances results in
61+
(results, raw_results)
62+
63+
let () =
64+
let all_results = benchmark () in
65+
let results, _ = all_results in
66+
67+
(* Extract timing data from the actual benchmark results *)
68+
let result_groups =
69+
Hashtbl.fold
70+
(fun _ v a -> Hashtbl.fold (fun k v a -> (k, v) :: a) v [] :: a)
71+
results []
72+
in
73+
74+
(* Find the monotonic-clock result group (timing data) *)
75+
let timing_group =
76+
match result_groups with _ :: _ :: timing :: _ -> Some timing | _ -> None
77+
in
78+
79+
let get_timing test_name =
80+
match timing_group with
81+
| None ->
82+
None
83+
| Some group -> (
84+
match List.assoc_opt test_name group with
85+
| Some estimator -> (
86+
let estimates = Analyze.OLS.estimates estimator in
87+
match estimates with Some (x :: _) -> Some x | _ -> None
88+
)
89+
| None ->
90+
None
91+
)
92+
in
93+
94+
Printf.printf "\n=== Performance Comparison: Optimized vs Reference ===\n\n" ;
95+
96+
let sizes = ["100"; "500"; "1000"] in
97+
List.iter
98+
(fun size ->
99+
Printf.printf "String size %s:\n" size ;
100+
let opt_test = Printf.sprintf "escaped-comparison/escaped %s" size in
101+
let ref_test = Printf.sprintf "escaped-comparison/escaped-spec %s" size in
102+
match (get_timing opt_test, get_timing ref_test) with
103+
| Some opt_time, Some ref_time ->
104+
let improvement = (ref_time -. opt_time) /. ref_time *. 100.0 in
105+
Printf.printf " Optimized: %.3f μs\n" opt_time ;
106+
Printf.printf " Reference: %.3f μs\n" ref_time ;
107+
Printf.printf " Improvement: %.1f%% %s\n\n" improvement
108+
(if improvement > 0.0 then "faster" else "slower")
109+
| None, _ ->
110+
Printf.printf " Optimized implementation data missing\n\n"
111+
| _, None ->
112+
Printf.printf " Reference implementation data missing\n\n"
113+
)
114+
sizes ;
115+
116+
Printf.printf "\n=== Detailed Results ===\n" ;
117+
match result_groups with
118+
| [results] ->
119+
let print (k, ols) = Fmt.pr "%s: %a\n%!" k Analyze.OLS.pp ols in
120+
List.iter print results
121+
| results_list ->
122+
Printf.printf "Results structure: %d result groups\n"
123+
(List.length results_list) ;
124+
List.iteri
125+
(fun i results ->
126+
Printf.printf "Result group %d:\n" i ;
127+
let print (k, ols) = Fmt.pr " %s: %a\n%!" k Analyze.OLS.pp ols in
128+
List.iter print results
129+
)
130+
results_list
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
(executable
2+
(name bench_xstringext)
3+
(modes exe)
4+
(optional)
5+
(libraries bechamel xapi-stdext-std bechamel-notty notty.unix fmt)
6+
)

0 commit comments

Comments
 (0)