|
| 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 |
0 commit comments