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 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
|
(**************************************************************************************)
(* Copyright (C) 2010 Pietro Abate <pietro.abate@pps.jussieu.fr> *)
(* Copyright (C) 2010 Mancoosi Project *)
(* *)
(* This library is free software: you can redistribute it and/or modify *)
(* it under the terms of the GNU Lesser General Public License as *)
(* published by the Free Software Foundation, either version 3 of the *)
(* License, or (at your option) any later version. A special linking *)
(* exception to the GNU Lesser General Public License applies to this *)
(* library, see the COPYING file for more information. *)
(**************************************************************************************)
open ExtLib
type benchmark = float * (string, Benchmark.t list) Hashtbl.t
let string_of_date ut =
let tm = Unix.gmtime ut in
Printf.sprintf "%02d/%d/%d-%02d:%02d"
tm.Unix.tm_mday
(tm.Unix.tm_mon + 1)
(tm.Unix.tm_year + 1900)
tm.Unix.tm_hour
tm.Unix.tm_min
;;
(* -------------------------------------- *)
let rec pp_list ?(sep="") pp_element fmt = function
|[h] -> Format.fprintf fmt "%a" pp_element h
|h::t ->
Format.fprintf fmt "%a%s@,%a"
pp_element h sep (pp_list ~sep pp_element) t
|[] -> ()
let pp_header widths fmt header =
let first_row = Array.map (fun x -> String.make (x + 1) ' ') widths in
Array.iteri (fun j cell ->
Format.pp_set_tab fmt ();
for z=0 to (String.length header.(j)) - 1 do cell.[z] <- header.(j).[z] done;
Format.fprintf fmt "%s" cell
) first_row
let pp_row pp_cell fmt row =
Array.iteri (fun j cell ->
Format.pp_print_tab fmt ();
Format.fprintf fmt "%a" pp_cell cell
) row
let pp_tables pp_row fmt (header,table) =
(* we build with the largest length of each column of the
* table and header *)
let widths = Array.create (Array.length table.(0)) 0 in
Array.iter (fun row ->
Array.iteri (fun j cell ->
widths.(j) <- max (String.length cell) widths.(j)
) row
) table;
Array.iteri (fun j cell ->
widths.(j) <- max (String.length cell) widths.(j)
) header;
(* open the table box *)
Format.pp_open_tbox fmt ();
(* print the header *)
Format.fprintf fmt "%a@\n" (pp_header widths) header;
(* print the table *)
Array.iter (pp_row fmt) table;
(* close the box *)
Format.pp_close_tbox fmt ()
;;
(* Parsing *)
let parse_test s =
(* 1283502697.79 WALL ( 0.14 usr + 0.04 sys = 0.18 CPU) @ 27.17/s (n=5) *)
let d_re = "[0-9]+" in
let t_re = Printf.sprintf "[ \\t]*\\(%s\\.%s\\)" d_re d_re in
let s_re = Str.regexp (
Printf.sprintf
"^%s WALL (%s usr \\+ %s sys = %s CPU) @ %s/s (n=\\(%s\\))$"
t_re t_re t_re t_re t_re d_re
)
in
let ex n s = float_of_string (Str.matched_group n s) in
if Str.string_match s_re s 0 then
{ Benchmark.wall = ex 1 s;
utime = ex 2 s;
stime = ex 3 s;
cutime = 0.;
cstime = 0.;
iters = Int64.of_string (Str.matched_group 6 s)
}
else
failwith (Printf.sprintf "invalid test %s" s)
let parse_sample s =
let s_re = Str.regexp "^\\([a-zA-Z0-9_.]+\\) : \\(.*\\)$" in
if Str.string_match s_re s 0 then
let fname = Str.matched_group 1 s in
let sl = Str.split (Str.regexp ",") (Str.matched_group 2 s) in
(fname, List.map parse_test sl)
else
failwith (Printf.sprintf "invalid sample %s" s)
(* "parse_date s" extracts the date from a date-string of a specific format.
e.g. parse_date "date 12345" = 12345 *)
let parse_date s =
let date_regexp = Pcre.regexp "^date ([0-9]+)$" in
try
let substrings = Pcre.exec ~rex:date_regexp s in
float_of_string(Pcre.get_substring substrings 1)
with Not_found -> failwith (Printf.sprintf "invalid date %s" s)
let parse_benchmark filename =
let ic = open_in filename in
let d = parse_date (input_line ic) in
let h = Hashtbl.create 17 in
begin try while true do
let (f,l) = parse_sample (input_line ic) in
Hashtbl.add h f l
done with End_of_file -> close_in ic end;
(d,h)
(* -------------------------------------- *)
(* Printing *)
let pp_benchmark fmt (ut,h) =
let pp_t fmt t = Format.fprintf fmt "%s" (Benchmark.to_string ~fdigits:6 t) in
Format.fprintf fmt "date %.f@." ut;
Hashtbl.iter (fun s tl ->
Format.fprintf fmt "%s : @[<h>%a@]@," s (pp_list ~sep:"," pp_t) tl
) h
;;
let save_benchmark ?(dirname=".benchmarks") (ut,h) =
let fname = Printf.sprintf "%.f.bench" ut in
if not(Sys.file_exists dirname) then Unix.mkdir dirname 0o777 ;
let file = (Filename.concat dirname (Filename.basename fname)) in
let oc = open_out file in
let fmt = Format.formatter_of_out_channel oc in
Format.fprintf fmt "%a" pp_benchmark (ut,h) ;
close_out oc
;;
let by_date x y = int_of_float ((fst x) -. (fst y))
let parse_benchmarks ?(days=7) ?(dirname=".benchmarks") () =
let l = ref [] in
let a = Sys.readdir dirname in
if Array.length a > 0 then
for i=0 to (min days ((Array.length a)-1)); do
let fname = a.(i) in
let file = (Filename.concat dirname (Filename.basename fname)) in
let (date,h) = parse_benchmark file in
l := (date,h)::!l
done;
List.sort ~cmp:by_date !l
module StringSet = Set.Make(String)
let pp_benchmarks fmt data =
if List.length data = 0 then
Format.fprintf fmt "Sample Set empty, nothing to print"
else begin
let error = 0.001 in
let fa =
Array.of_list (
StringSet.elements (
List.fold_left (fun s (_,h) ->
Hashtbl.fold (fun k _ s -> StringSet.add k s) h s
) StringSet.empty data
)
)
in
let func_size = Array.length fa in
let data_size = List.length data in
let pp_cell fmt e = Format.fprintf fmt "%s" e in
let h = Array.init (func_size+1) (function 0 -> "Date" |n -> fa.(n-1)) in
let t = Array.make_matrix (List.length data) (func_size+1) "" in
let last = Array.make func_size max_float in
let diff a b = (abs_float(a -. b)) > error in
List.iteri (fun i (ut,h) ->
(* we need to consider the list from the less recent to the more recent, but
* then I we want to print the from the most recent to the less recent *)
let i = data_size - i -1 in
t.(i).(0) <- string_of_date ut;
for j = 0 to func_size-1 do
let avg =
try
match Hashtbl.find h fa.(j) with
|[] -> "n/a"
|h::_ -> begin
(* XXX : I should only compare up to 3 decimal digits *)
let a = h.Benchmark.utime /. Int64.to_float(h.Benchmark.iters) in
let res =
if diff last.(j) a && last.(j) > 0. && a > last.(j) then
Printf.sprintf "%.03f(*)" a
else
Printf.sprintf "%.03f" a
in
if a < last.(j) then last.(j) <- a;
res
end
with Not_found -> "X"
in
t.(i).(j+1) <- avg
done
) data;
pp_tables (pp_row pp_cell) fmt (h,t)
end
;;
let make_benchmark l =
let h = Hashtbl.create (List.length l) in
List.iter (fun (s,sl) -> Hashtbl.add h s sl) l;
(Unix.time(),h)
module Options = struct
open OptParse
let verbose = StdOpt.incr_option ()
let run = StdOpt.store_true ()
let save = StdOpt.store_false ()
let show = StdOpt.store_false ()
let description = ""
let options = OptParser.make ~description:description ()
open OptParser
add options ~short_name:'v' ~help:"Print information (can be repeated)" verbose;
add options ~short_name:'r' ~long_name:"run" ~help:"run all tests" run;
add options ~long_name:"nosave" ~help:"not save test results" save;
add options ~long_name:"noshow" ~help:"not show test results" show;
end
let main run =
ignore(OptParse.OptParser.parse_argv Options.options);
if OptParse.Opt.get Options.run then begin
let b = make_benchmark (run ()) in
if OptParse.Opt.get Options.save then
save_benchmark b
else if not(OptParse.Opt.get Options.show) then
Format.printf "%a@." pp_benchmarks [b]
end ;
(* this will also read the new benchmark *)
if OptParse.Opt.get Options.show then
let l = parse_benchmarks () in
Format.printf "%a@." pp_benchmarks l
;;
|