summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephane Glondu <steph@glondu.net>2020-08-25 07:00:43 +0200
committerStephane Glondu <steph@glondu.net>2020-08-25 07:00:43 +0200
commitb77c4da1a30c0db71de9bf48c5b85bc47f9c5210 (patch)
tree12f3512802b4e7042fc175c00fcc5d204a506bc0
parent7db70fe2b1be8b026b29e14463a63ad914a8cc1f (diff)
New upstream version 1.4
-rw-r--r--META4
-rw-r--r--_oasis21
-rw-r--r--_tags24
-rw-r--r--benchmark.ml261
-rw-r--r--benchmark.mli136
-rw-r--r--myocamlbuild.ml88
-rw-r--r--setup.ml229
-rw-r--r--tests/tree.ml22
8 files changed, 647 insertions, 138 deletions
diff --git a/META b/META
index 657b541..5869ad4 100644
--- a/META
+++ b/META
@@ -1,6 +1,6 @@
# OASIS_START
-# DO NOT EDIT (digest: 8d589cce128284ea37136fa3315db0ab)
-version = "1.3.1"
+# DO NOT EDIT (digest: d46739ab84ae5c81a14032b8a0cb2453)
+version = "1.4"
description = "Benchmark running times of code."
requires = "unix"
archive(byte) = "benchmark.cma"
diff --git a/_oasis b/_oasis
index 63c1c5b..78ff732 100644
--- a/_oasis
+++ b/_oasis
@@ -1,15 +1,17 @@
# -*-conf-*-
-OASISFormat: 0.3
+OASISFormat: 0.4
Name: benchmark
-Version: 1.3.1
+Version: 1.4
Synopsis: Benchmark running times of code.
Authors: Christophe Troestler <Christophe.Troestler@umons.ac.be>
+Maintainers: Christophe Troestler <Christophe.Troestler@umons.ac.be>
License: LGPL-3.0 with OCaml linking exception
Description: This module provides a set of tools to measure the running times
of your functions and to easily compare the results. A statistical
test is used to determine whether the results truly differ.
Plugins: META (0.2)
Homepage: http://ocaml-benchmark.forge.ocamlcore.org/
+OCamlVersion: >= 3.12.0
Flag examples
Description: Whether to compile the examples.
@@ -130,7 +132,16 @@ Executable long_run
CompiledObject: best
Install: false
+Executable tree
+ Build$: flag(tests)
+ Path: tests
+ MainIs: tree.ml
+ BuildTools: ocamlbuild
+ BuildDepends: benchmark
+ CompiledObject: best
+ Install: false
+
SourceRepository trunk
- Type: svn
- Location: svn://scm.ocamlcore.org/svn/ocaml-benchmark/trunk
- Browser: https://forge.ocamlcore.org/scm/browser.php?group_id=197
+ Type: git
+ Location: https://github.com/Chris00/ocaml-benchmark.git
+ Browser: https://github.com/Chris00/ocaml-benchmark
diff --git a/_tags b/_tags
index ecd13d3..720836d 100644
--- a/_tags
+++ b/_tags
@@ -1,8 +1,9 @@
# OASIS_START
-# DO NOT EDIT (digest: 17f396b5386ca66b9662796db29eb18c)
+# DO NOT EDIT (digest: 23c578b63f53f29d8fe090eaed8ca940)
# Ignore VCS directories, you can use the same kind of rule outside
# OASIS_START/STOP if you want to exclude directories that contains
# useless stuff for the build process
+true: annot, bin_annot
<**/.svn>: -traverse
<**/.svn>: not_hygienic
".bzr": -traverse
@@ -15,7 +16,7 @@
"_darcs": not_hygienic
# Library benchmark
"benchmark.cmxs": use_benchmark
-<*.ml{,i}>: pkg_unix
+<*.ml{,i,y}>: pkg_unix
# Executable ar_ba
<examples/ar_ba.{native,byte}>: pkg_bigarray
<examples/ar_ba.{native,byte}>: pkg_unix
@@ -45,22 +46,25 @@
<examples/regexps.{native,byte}>: pkg_str
<examples/regexps.{native,byte}>: pkg_unix
<examples/regexps.{native,byte}>: use_benchmark
-<examples/*.ml{,i}>: pkg_pcre
-<examples/*.ml{,i}>: pkg_str
+<examples/*.ml{,i,y}>: pkg_pcre
+<examples/*.ml{,i,y}>: pkg_str
# Executable try_if
<examples/try_if.{native,byte}>: pkg_bigarray
<examples/try_if.{native,byte}>: pkg_unix
<examples/try_if.{native,byte}>: use_benchmark
-<examples/*.ml{,i}>: pkg_bigarray
+<examples/*.ml{,i,y}>: pkg_bigarray
# Executable func_record
<examples/func_record.{native,byte}>: pkg_unix
<examples/func_record.{native,byte}>: use_benchmark
-<examples/*.ml{,i}>: pkg_unix
-<examples/*.ml{,i}>: use_benchmark
+<examples/*.ml{,i,y}>: pkg_unix
+<examples/*.ml{,i,y}>: use_benchmark
# Executable long_run
<tests/long_run.{native,byte}>: pkg_unix
<tests/long_run.{native,byte}>: use_benchmark
-<tests/*.ml{,i}>: pkg_unix
-<tests/*.ml{,i}>: use_benchmark
+# Executable tree
+<tests/tree.{native,byte}>: pkg_unix
+<tests/tree.{native,byte}>: use_benchmark
+<tests/*.ml{,i,y}>: pkg_unix
+<tests/*.ml{,i,y}>: use_benchmark
# OASIS_STOP
-true: strict_formats
+true: strict_formats, safe_string
diff --git a/benchmark.ml b/benchmark.ml
index 46fb9bc..c96caf2 100644
--- a/benchmark.ml
+++ b/benchmark.ml
@@ -305,7 +305,7 @@ let make_printer nspace =
let null_printer = { print_indent = (fun _ -> ()); print = (fun _ -> ()) }
-(* Generic interface for performing measurments on a list of functions *)
+(* Generic interface for performing measurements on a list of functions *)
let testN ~test default_f_name ?min_count ?min_cpu ~style
?fwidth ?fdigits ~repeat funs =
let length_name =
@@ -614,3 +614,262 @@ let tabulate ?(no_parent=false) ?(confidence=0.95) results =
row_formatter top_row;
List.iter row_formatter rows;
flush stdout
+
+(** {2 Bench Tree} *)
+
+module Tree = struct
+ (** {2 Path} *)
+
+ type path = string list
+
+ let print_path_element fmt p =
+ Format.pp_print_char fmt '.';
+ Format.pp_print_cut fmt ();
+ Format.pp_print_string fmt p
+
+ let print_path fmt path =
+ Format.fprintf fmt "@[<2>";
+ (match path with
+ | [] -> ()
+ | [p] -> Format.pp_print_string fmt p
+ | p :: tl -> Format.pp_print_string fmt p;
+ List.iter (print_path_element fmt) tl);
+ Format.fprintf fmt "@]"
+
+ (* Split the string along "." characters. Specification:
+ assert (parse_path "foo.bar" = ["foo";"bar"]);
+ assert (parse_path "foo" = ["foo"]);
+ assert (parse_path "" = [""])
+ *)
+ let rev_parse_path check_name s =
+ let l = ref [] in
+ let i0 = ref 0 in
+ for i = 0 to String.length s - 1 do
+ if String.unsafe_get s i = '.' then (
+ let name = String.sub s !i0 (i - !i0) in
+ check_name name;
+ l := name :: !l;
+ i0 := i + 1;
+ )
+ done;
+ let name = if !i0 = 0 then s
+ else String.sub s !i0 (String.length s - !i0) in
+ check_name name;
+ name :: !l
+
+ let check_reserved name =
+ if name = "*" then invalid_arg "Name \"*\" is reserved for wildcard"
+
+ let check_nothing _ = ()
+
+ let parse_path s =
+ List.rev(rev_parse_path check_nothing s)
+
+
+ (** {2 Bench Tree} *)
+
+ module SMap = Map.Make(String)
+
+ (* A collection of benchmarks with fast concatenation. *)
+ type benches = Single of samples Lazy.t
+ | Pair of benches * benches
+
+ let merge_benches_opt b1 b2 = match b1, b2 with
+ | None, b | b, None -> b
+ | Some b1, Some b2 -> Some(Pair(b1, b2))
+
+ let rec number_of_benches = function
+ | Single _ -> 1
+ | Pair(b1, b2) -> number_of_benches b1 + number_of_benches b2
+
+ let rec benches_iter benches ~f = match benches with
+ | Single b -> f b
+ | Pair(b1, b2) -> benches_iter b1 ~f; benches_iter b2 ~f
+
+ type t = Tree of benches option * t SMap.t
+ (* benches at that level + named sublevels. The name "" is
+ understood as "at this level" and so will not be present in the
+ map. *)
+
+ let empty = Tree(None, SMap.empty)
+
+ let is_empty (Tree(b, m)) =
+ b = None && SMap.is_empty m
+
+ let rec merge (Tree(b1, m1)) (Tree(b2, m2)) : t =
+ let b = merge_benches_opt b1 b2 in
+ let m = SMap.merge merge_opt m1 m2 in
+ Tree(b, m)
+ and merge_opt _ o1 o2 = match o1, o2 with
+ | None, None -> None
+ | Some o, None
+ | None, Some o -> Some o
+ | Some o1, Some o2 -> Some (merge o1 o2)
+
+ let concat l = List.fold_left merge empty l
+
+ let check_allowed_name n =
+ if n = "*" then invalid_arg "Name \"*\" is reserved for wildcard";
+ for i = 0 to String.length n - 1 do
+ if String.unsafe_get n i = '.' then
+ invalid_arg "Names cannot contain dots"
+ done
+
+ let of_bench bench = Tree(Some(Single bench), SMap.empty)
+
+ let name_nonempty t n = Tree(None, SMap.singleton n t)
+
+ let name t n =
+ (* Assume the name [n] is valid *)
+ if n = "" then t else name_nonempty t n
+
+ (* prefix a tree with a path. Now the whole tree is only reachable
+ from this given path *)
+ let prefix path t =
+ List.fold_right (fun n t -> check_reserved n; name t n) path t
+
+ let ( @>> ) n t =
+ let path = rev_parse_path check_reserved n in
+ List.fold_left name t path
+
+ let ( @> ) name bench = name @>> (of_bench bench)
+
+ let (@>>>) n l = n @>> (concat l)
+
+ let with_int f = function
+ | [] -> empty
+ | l ->
+ let g i = Tree(None, SMap.singleton (string_of_int i) (f i)) in
+ concat (List.map g l)
+
+ (* print the structure of the tree, to show the user possible paths *)
+ let rec print_tree_map fmt m =
+ SMap.iter (print_tree_path fmt) m
+ and print_tree_path fmt name (Tree(b, m)) =
+ (match b with
+ | None -> Format.fprintf fmt "@\n@[<2>- %s" name
+ | Some b ->
+ let n = number_of_benches b in
+ Format.fprintf fmt "@\n@[<2>- %s: %i benchmark%s"
+ name n (if n > 1 then "s" else ""));
+ print_tree_map fmt m;
+ Format.fprintf fmt "@]"
+
+ let print fmt (Tree(b, m)) =
+ (match b with
+ | None -> Format.fprintf fmt "No benchmark at root"
+ | Some b ->
+ let n = number_of_benches b in
+ Format.fprintf fmt "%i benchmark%s at root"
+ n (if n > 1 then "s" else ""));
+ print_tree_map fmt m
+
+ (** {2 Selecting a subtree} *)
+
+ let rec filter path (Tree(b,m) as t) = match path with
+ | [] -> t
+ | [""] -> (* Only return the benches at this level (no sub-levels) *)
+ Tree(b, SMap.empty)
+ | "" :: tl -> (* skip empty component NOT at the end, skip *)
+ filter tl t
+ | "*" :: tl ->
+ (* wildcard pattern, select all subtrees *)
+ let map_filter name t m =
+ let t = filter tl t in
+ (* Keep it only if not empty. *)
+ if is_empty t then m else SMap.add name t m in
+ Tree(b, SMap.fold map_filter m SMap.empty)
+ | p0 :: tl ->
+ match (try Some(SMap.find p0 m) with Not_found -> None) with
+ | None -> empty
+ | Some t -> let t = filter tl t in
+ (* propagate up the emptiness *)
+ if is_empty t then empty else name_nonempty t p0
+
+ (** {2 Run} *)
+
+ let print_sep fmt =
+ Format.pp_print_string fmt "***********************************\
+ ***********************************";
+ Format.pp_print_newline fmt ()
+
+ let run_bench_path fmt is_previous_output rev_path = function
+ | None -> is_previous_output
+ | Some b ->
+ if is_previous_output then print_sep fmt;
+ Format.fprintf fmt "*** Run benchmarks for path \"%a\"@\n@."
+ print_path (List.rev rev_path);
+ benches_iter b ~f:(fun b -> tabulate (Lazy.force b));
+ true
+
+ let rec run_all fmt is_previous_output rev_path (Tree(b, m)) =
+ let is_previous_output =
+ run_bench_path fmt is_previous_output rev_path b in
+ SMap.fold (fun name t is_out -> run_all fmt is_out (name :: rev_path) t)
+ m is_previous_output
+
+ let run_1path fmt t is_previous_output path =
+ (* Filtering the tree keep its full paths so we initialize
+ [rev_path] to [[]]. *)
+ run_all fmt is_previous_output [] (filter path t)
+
+ let run_paths fmt ~paths t =
+ let is_out = List.fold_left (run_1path fmt t) false paths in
+ if not is_out then
+ match paths with
+ | [] -> Format.fprintf fmt "No benchmark to run.@\n@."
+ | p0 :: tl ->
+ Format.fprintf fmt "No benchmark to run for paths ";
+ print_path fmt p0;
+ List.iter (fun p -> print_path fmt p;
+ Format.pp_print_string fmt ", ") tl;
+ Format.fprintf fmt ".@\n@."
+
+ type arg_state = { mutable paths : path list;
+ mutable print_tree : bool;
+ }
+ let arg () =
+ let st = { paths = []; print_tree = false } in
+ let add_path s = st.paths <- parse_path s :: st.paths in
+ let options =
+ [ "--path", Arg.String add_path, " only apply to subpath"
+ ; "-p", Arg.String add_path, " short option for --path"
+ ; "--tree", Arg.Unit (fun () -> st.print_tree <- true), " print the tree"
+ ] in
+ st, options
+
+ let run ?arg ?(paths=[]) ?(out=Format.std_formatter) t =
+ match arg with
+ | None -> run_paths out ~paths t
+ | Some st ->
+ if st.print_tree then
+ Format.fprintf out "@[%a@]@." print t
+ else
+ run_paths out ~paths:(paths @ List.rev st.paths) t
+
+ (** {2 Global Registration} *)
+
+ (* the global tree of benchmarks *)
+ let tree = ref empty
+
+ let global () = !tree
+
+ let register new_t =
+ tree := merge !tree new_t
+
+ let run_global ?(argv=Sys.argv) ?(out=Format.std_formatter) () =
+ let st, specs = arg () in
+ let no_anon _ = raise(Arg.Bad "No anonymous arguments allowed") in
+ let pgm = try Filename.basename Sys.argv.(0)
+ with _ -> "run benchmark" in
+ let usage = pgm ^ " [options]" in
+ try
+ Arg.parse_argv argv specs no_anon usage;
+ run ~arg:st ~out !tree
+ with Arg.Bad msg ->
+ Format.fprintf out "%s@." msg
+end
+
+(* Local Variables: *)
+(* compile-command: "make -k" *)
+(* End: *)
diff --git a/benchmark.mli b/benchmark.mli
index 514ea20..c55e630 100644
--- a/benchmark.mli
+++ b/benchmark.mli
@@ -228,3 +228,139 @@ val tabulate : ?no_parent:bool -> ?confidence:float -> samples -> unit
@param confidence is used to determine the confidence interval for
the Student's test. (default: [0.95]). *)
+
+
+(** {2 Benchmark Tree}
+
+ Naming benchmarks within a hierarchy that allows to run them all,
+ or filter them so that only a subset is run. *)
+
+module Tree : sig
+ type t
+ (** A (possibly empty) tree of benchmarks. Individual benchmarks
+ (i.e., calls to {!throughputN}, {!latencyN}, etc. wrapped with
+ {!(>:)}) can appear at any node of the tree. The edges are
+ annotated with strings, and paths (see {!path}) are used to
+ select subtrees. *)
+
+ val ( @> ) : string -> samples Lazy.t -> t
+ (** [name @> bench] returns a (named) node of the benchmark tree.
+ If evaluated, it simply returns samples (for instance using
+ {!throughputN}). If the name contains dots, it is interpreted
+ as a path. For examle ["a.b" @> bench] is equivalent to ["a" @>>
+ "b" @> bench].
+
+ Example (the lazy thunk is used to hide initialization code):
+
+ {[
+ Benchmark.Tree.(
+ "sort" >: lazy
+ (let a = Array.init 1_000_000 (fun i -> i) in
+ Benchmark.throughput1 18 (Array.sort compare) a
+ )
+ ) ;;
+ ]} *)
+
+ val ( @>> ) : string -> t -> t
+ (** [name >:: tree] makes [tree] accessible through the given
+ [name], i.e., prefix all paths in the tree by [name]. It has no
+ effect if [name = ""]. If the name contains dots, it is
+ interpreted as a path. For instance ["n1.n2" @>> tree] is
+ equivalent to ["n1" @>> "n2" @>> tree] and adds the path
+ [[n1;n2]] as a prefix to the tree.
+
+ @raise Invalid_argument is the name is invalid. At least names
+ corresponding to OCaml identifiers are valid. *)
+
+ val concat : t list -> t
+ (** Merge the given trees (recursively). Merging proceeds by taking the union
+ of all path heads in the list, and, for each such string [x],
+ merging recursively all subtrees reachable under [x].
+
+ For instance merging the trees [a.{b, c}], [a.b.d] and [{a.d, foo}]
+ will give the tree [{a.(b, b.d, c, d}, d}]. *)
+
+ val ( @>>> ) : string -> t list -> t
+ (** [name @>>> l] is equivalent to [name >:: concat l]. It names a list of
+ trees, and is useful to build lists of benchmarks related to some
+ common topic. If the name contains dots, it is interpreted
+ as a path.
+
+ @raise Invalid_argument is the name is invalid. At least names
+ corresponding to OCaml identifiers are valid. *)
+
+ val with_int : (int -> t) -> int list -> t
+ (** [with_int f l] parametrize trees with several integer values
+ (e.g. a size). The tree [f i] is prefixed with the label [i]. *)
+
+ val print : Format.formatter -> t -> unit
+ (** Print the tree of benchmarks (its structure) on the given formatter.
+ Useful in combination with the [path] argument of {!run} *)
+
+ (** {2 Path} *)
+
+ type path = string list
+ (** A path in a tree, pointing at a subtree. *)
+
+ val print_path : Format.formatter -> path -> unit
+
+ val parse_path : string -> path
+ (** Split a string into a path at the "." separators.
+ Example: [parse_path "a.b.c"] returns [["a"; "b"; "c"]]. *)
+
+ val prefix : path -> t -> t
+ (** Add the path as a prefix to the tree, similar to repeated
+ calls to [>::]. *)
+
+ val filter : path -> t -> t
+ (** [filter p t] return the tree obtained by keeping all the paths
+ in [t] that match the path [p].
+ Empty components [""] in the middle of the path are ignored.
+ Empty components [""] at the end of the path return only the
+ benchmarks at that level (i.e., one discards the benchmarks
+ pointed by paths of which [p] is a strict prefix).
+ The special path component ["*"] selects all subtrees at that
+ level (it acts as a wildcard). *)
+
+
+ (** {2 Running} *)
+
+ type arg_state
+
+ val arg : unit -> arg_state * (Arg.key * Arg.spec * Arg.doc) list
+ (** [arg ()] returns [(arg, specs)] where [arg] is a state coming
+ from parsing the command line using [specs]. The options are:
+ - "--path" or "-p" to add a sub-tree of benchmarks
+ - "--tree" to print the tree of benchmarks.
+ Note that the default state runs all benchmarks. You need to
+ use something like [Arg.parse (specs @ more_specs) ...] to make
+ the above arguments available to the program user. *)
+
+ val run : ?arg: arg_state -> ?paths: path list -> ?out: Format.formatter ->
+ t -> unit
+ (** [run t] runs all benchmarks of [t] and print the results to [fmt].
+ @param paths if provided, only the sub-trees corresponding to
+ these path is executed. Default: execute everything.
+ @param out The formatter on which to print the output.
+ Default: [Format.std_formatter].
+ @param arg use the result of the command line parsing to direct
+ the run. Default: run all paths in [path] *)
+
+
+ (** {2 Global Registration} *)
+
+ val global : unit -> t
+ (** Global tree, built from calls to {!register}. It is useful
+ to centralize all benchmarks at one place to, then, run them all *)
+
+ val register : t -> unit
+ (** Register a benchmark to the global registry of benchmarks. *)
+
+ val run_global :
+ ?argv:string array ->
+ ?out:Format.formatter ->
+ unit -> unit
+ (** Same as {!run} on the global tree of benchmarks and parsing the
+ command line arguments from [argv] (which is [Sys.argv] by
+ default). *)
+end
diff --git a/myocamlbuild.ml b/myocamlbuild.ml
index 4420e8e..78b2a6d 100644
--- a/myocamlbuild.ml
+++ b/myocamlbuild.ml
@@ -1,5 +1,5 @@
(* OASIS_START *)
-(* DO NOT EDIT (digest: 9eb145f6e2b004ab61babdd6aa609803) *)
+(* DO NOT EDIT (digest: da78aa0b7ff42be1e339410cde8aeb5c) *)
module OASISGettext = struct
(* # 22 "src/oasis/OASISGettext.ml" *)
@@ -249,6 +249,9 @@ module MyOCamlbuildFindlib = struct
*)
open Ocamlbuild_plugin
+ type conf =
+ { no_automatic_syntax: bool;
+ }
(* these functions are not really officially exported *)
let run_and_read =
@@ -315,7 +318,7 @@ module MyOCamlbuildFindlib = struct
(* This lists all supported packages. *)
let find_packages () =
- List.map before_space (split_nl & run_and_read "ocamlfind list")
+ List.map before_space (split_nl & run_and_read (exec_from_conf "ocamlfind" ^ " list"))
(* Mock to list available syntaxes. *)
@@ -338,7 +341,7 @@ module MyOCamlbuildFindlib = struct
]
- let dispatch =
+ let dispatch conf =
function
| After_options ->
(* By using Before_options one let command line options have an higher
@@ -357,31 +360,39 @@ module MyOCamlbuildFindlib = struct
* -linkpkg *)
flag ["ocaml"; "link"; "program"] & A"-linkpkg";
- (* For each ocamlfind package one inject the -package option when
- * compiling, computing dependencies, generating documentation and
- * linking. *)
- List.iter
- begin fun pkg ->
- let base_args = [A"-package"; A pkg] in
- (* TODO: consider how to really choose camlp4o or camlp4r. *)
- let syn_args = [A"-syntax"; A "camlp4o"] in
- let args =
- (* Heuristic to identify syntax extensions: whether they end in
- ".syntax"; some might not.
- *)
- if Filename.check_suffix pkg "syntax" ||
- List.mem pkg well_known_syntax then
- syn_args @ base_args
- else
- base_args
- in
- flag ["ocaml"; "compile"; "pkg_"^pkg] & S args;
- flag ["ocaml"; "ocamldep"; "pkg_"^pkg] & S args;
- flag ["ocaml"; "doc"; "pkg_"^pkg] & S args;
- flag ["ocaml"; "link"; "pkg_"^pkg] & S base_args;
- flag ["ocaml"; "infer_interface"; "pkg_"^pkg] & S args;
- end
- (find_packages ());
+ if not (conf.no_automatic_syntax) then begin
+ (* For each ocamlfind package one inject the -package option when
+ * compiling, computing dependencies, generating documentation and
+ * linking. *)
+ List.iter
+ begin fun pkg ->
+ let base_args = [A"-package"; A pkg] in
+ (* TODO: consider how to really choose camlp4o or camlp4r. *)
+ let syn_args = [A"-syntax"; A "camlp4o"] in
+ let (args, pargs) =
+ (* Heuristic to identify syntax extensions: whether they end in
+ ".syntax"; some might not.
+ *)
+ if Filename.check_suffix pkg "syntax" ||
+ List.mem pkg well_known_syntax then
+ (syn_args @ base_args, syn_args)
+ else
+ (base_args, [])
+ in
+ flag ["ocaml"; "compile"; "pkg_"^pkg] & S args;
+ flag ["ocaml"; "ocamldep"; "pkg_"^pkg] & S args;
+ flag ["ocaml"; "doc"; "pkg_"^pkg] & S args;
+ flag ["ocaml"; "link"; "pkg_"^pkg] & S base_args;
+ flag ["ocaml"; "infer_interface"; "pkg_"^pkg] & S args;
+
+ (* TODO: Check if this is allowed for OCaml < 3.12.1 *)
+ flag ["ocaml"; "compile"; "package("^pkg^")"] & S pargs;
+ flag ["ocaml"; "ocamldep"; "package("^pkg^")"] & S pargs;
+ flag ["ocaml"; "doc"; "package("^pkg^")"] & S pargs;
+ flag ["ocaml"; "infer_interface"; "package("^pkg^")"] & S pargs;
+ end
+ (find_packages ());
+ end;
(* Like -package but for extensions syntax. Morover -syntax is useless
* when linking. *)
@@ -546,12 +557,13 @@ module MyOCamlbuildBase = struct
(* When ocaml link something that use the C library, then one
need that file to be up to date.
+ This holds both for programs and for libraries.
*)
- dep ["link"; "ocaml"; "program"; tag_libstubs lib]
- [dir/"lib"^(nm_libstubs lib)^"."^(!Options.ext_lib)];
+ dep ["link"; "ocaml"; tag_libstubs lib]
+ [dir/"lib"^(nm_libstubs lib)^"."^(!Options.ext_lib)];
- dep ["compile"; "ocaml"; "program"; tag_libstubs lib]
- [dir/"lib"^(nm_libstubs lib)^"."^(!Options.ext_lib)];
+ dep ["compile"; "ocaml"; tag_libstubs lib]
+ [dir/"lib"^(nm_libstubs lib)^"."^(!Options.ext_lib)];
(* TODO: be more specific about what depends on headers *)
(* Depends on .h files *)
@@ -580,18 +592,18 @@ module MyOCamlbuildBase = struct
()
- let dispatch_default t =
+ let dispatch_default conf t =
dispatch_combine
[
dispatch t;
- MyOCamlbuildFindlib.dispatch;
+ MyOCamlbuildFindlib.dispatch conf;
]
end
-# 594 "myocamlbuild.ml"
+# 606 "myocamlbuild.ml"
open Ocamlbuild_plugin;;
let package_default =
{
@@ -602,8 +614,10 @@ let package_default =
}
;;
-let dispatch_default = MyOCamlbuildBase.dispatch_default package_default;;
+let conf = {MyOCamlbuildFindlib.no_automatic_syntax = false}
+
+let dispatch_default = MyOCamlbuildBase.dispatch_default conf package_default;;
-# 608 "myocamlbuild.ml"
+# 622 "myocamlbuild.ml"
(* OASIS_STOP *)
Ocamlbuild_plugin.dispatch dispatch_default;;
diff --git a/setup.ml b/setup.ml
index 8f570f8..37578ac 100644
--- a/setup.ml
+++ b/setup.ml
@@ -3,9 +3,9 @@ let () =
with Not_found -> ();;
(* OASIS_START *)
-(* DO NOT EDIT (digest: 570f0cf455bae2020373f483beb84fb7) *)
+(* DO NOT EDIT (digest: ed8b6a6d5d6899833e2d5502e0896aa5) *)
(*
- Regenerated by OASIS v0.4.4
+ Regenerated by OASIS v0.4.5
Visit http://oasis.forge.ocamlcore.org for more information and
documentation about functions used in this file.
*)
@@ -244,11 +244,9 @@ module OASISString = struct
let replace_chars f s =
- let buf = String.make (String.length s) 'X' in
- for i = 0 to String.length s - 1 do
- buf.[i] <- f s.[i]
- done;
- buf
+ let buf = Buffer.create (String.length s) in
+ String.iter (fun c -> Buffer.add_char buf (f c)) s;
+ Buffer.contents buf
end
@@ -1731,6 +1729,13 @@ module OASISFeatures = struct
(fun () ->
s_ "Allows the OASIS section comments and digest to be omitted in \
generated files.")
+
+ let no_automatic_syntax =
+ create "no_automatic_syntax" alpha
+ (fun () ->
+ s_ "Disable the automatic inclusion of -syntax camlp4o for packages \
+ that matches the internal heuristic (if a dependency ends with \
+ a .syntax or is a well known syntax).")
end
module OASISUnixPath = struct
@@ -2101,16 +2106,6 @@ module OASISLibrary = struct
lst
in
- (* The headers that should be compiled along *)
- let headers =
- if lib.lib_pack then
- []
- else
- find_modules
- lib.lib_modules
- "cmi"
- in
-
(* The .cmx that be compiled along *)
let cmxs =
let should_be_built =
@@ -2136,12 +2131,32 @@ module OASISLibrary = struct
[]
in
+ (* The headers and annot/cmt files that should be compiled along *)
+ let headers =
+ let sufx =
+ if lib.lib_pack
+ then [".cmti"; ".cmt"; ".annot"]
+ else [".cmi"; ".cmti"; ".cmt"; ".annot"]
+ in
+ List.map
+ begin
+ List.fold_left
+ begin fun accu s ->
+ let dot = String.rindex s '.' in
+ let base = String.sub s 0 dot in
+ List.map ((^) base) sufx @ accu
+ end
+ []
+ end
+ (find_modules lib.lib_modules "cmi")
+ in
+
(* Compute what libraries should be built *)
let acc_nopath =
(* Add the packed header file if required *)
let add_pack_header acc =
if lib.lib_pack then
- [cs.cs_name^".cmi"] :: acc
+ [cs.cs_name^".cmi"; cs.cs_name^".cmti"; cs.cs_name^".cmt"] :: acc
else
acc
in
@@ -2501,13 +2516,13 @@ module OASISFindlib = struct
in
let library_name_of_findlib_name =
- Lazy.lazy_from_fun
- (fun () ->
- (* Revert findlib_name_of_library_name. *)
- MapString.fold
- (fun k v mp -> MapString.add v k mp)
- fndlb_name_of_lib_name
- MapString.empty)
+ lazy begin
+ (* Revert findlib_name_of_library_name. *)
+ MapString.fold
+ (fun k v mp -> MapString.add v k mp)
+ fndlb_name_of_lib_name
+ MapString.empty
+ end
in
let library_name_of_findlib_name fndlb_nm =
try
@@ -2877,7 +2892,7 @@ module OASISFileUtil = struct
end
-# 2878 "setup.ml"
+# 2893 "setup.ml"
module BaseEnvLight = struct
(* # 22 "src/base/BaseEnvLight.ml" *)
@@ -2982,7 +2997,7 @@ module BaseEnvLight = struct
end
-# 2983 "setup.ml"
+# 2998 "setup.ml"
module BaseContext = struct
(* # 22 "src/base/BaseContext.ml" *)
@@ -5393,7 +5408,7 @@ module BaseSetup = struct
end
-# 5394 "setup.ml"
+# 5409 "setup.ml"
module InternalConfigurePlugin = struct
(* # 22 "src/plugins/internal/InternalConfigurePlugin.ml" *)
@@ -5829,6 +5844,17 @@ module InternalInstallPlugin = struct
lst
in
+ let make_fnames modul sufx =
+ List.fold_right
+ begin fun sufx accu ->
+ (String.capitalize modul ^ sufx) ::
+ (String.uncapitalize modul ^ sufx) ::
+ accu
+ end
+ sufx
+ []
+ in
+
(** Install all libraries *)
let install_libs pkg =
@@ -5849,27 +5875,29 @@ module InternalInstallPlugin = struct
OASISHostPath.of_unix bs.bs_path
in
List.fold_left
- (fun acc modul ->
- try
- List.find
- OASISFileUtil.file_exists_case
- (List.map
- (Filename.concat path)
- [modul^".mli";
- modul^".ml";
- String.uncapitalize modul^".mli";
- String.capitalize modul^".mli";
- String.uncapitalize modul^".ml";
- String.capitalize modul^".ml"])
- :: acc
- with Not_found ->
- begin
- warning
- (f_ "Cannot find source header for module %s \
- in library %s")
- modul cs.cs_name;
- acc
- end)
+ begin fun acc modul ->
+ begin
+ try
+ [List.find
+ OASISFileUtil.file_exists_case
+ (List.map
+ (Filename.concat path)
+ (make_fnames modul [".mli"; ".ml"]))]
+ with Not_found ->
+ warning
+ (f_ "Cannot find source header for module %s \
+ in library %s")
+ modul cs.cs_name;
+ []
+ end
+ @
+ List.filter
+ OASISFileUtil.file_exists_case
+ (List.map
+ (Filename.concat path)
+ (make_fnames modul [".annot";".cmti";".cmt"]))
+ @ acc
+ end
acc
lib.lib_modules
in
@@ -5917,27 +5945,29 @@ module InternalInstallPlugin = struct
OASISHostPath.of_unix bs.bs_path
in
List.fold_left
- (fun acc modul ->
- try
- List.find
- OASISFileUtil.file_exists_case
- (List.map
- (Filename.concat path)
- [modul^".mli";
- modul^".ml";
- String.uncapitalize modul^".mli";
- String.capitalize modul^".mli";
- String.uncapitalize modul^".ml";
- String.capitalize modul^".ml"])
- :: acc
- with Not_found ->
- begin
- warning
- (f_ "Cannot find source header for module %s \
- in object %s")
- modul cs.cs_name;
- acc
- end)
+ begin fun acc modul ->
+ begin
+ try
+ [List.find
+ OASISFileUtil.file_exists_case
+ (List.map
+ (Filename.concat path)
+ (make_fnames modul [".mli"; ".ml"]))]
+ with Not_found ->
+ warning
+ (f_ "Cannot find source header for module %s \
+ in object %s")
+ modul cs.cs_name;
+ []
+ end
+ @
+ List.filter
+ OASISFileUtil.file_exists_case
+ (List.map
+ (Filename.concat path)
+ (make_fnames modul [".annot";".cmti";".cmt"]))
+ @ acc
+ end
acc
obj.obj_modules
in
@@ -6242,7 +6272,7 @@ module InternalInstallPlugin = struct
end
-# 6243 "setup.ml"
+# 6273 "setup.ml"
module OCamlbuildCommon = struct
(* # 22 "src/plugins/ocamlbuild/OCamlbuildCommon.ml" *)
@@ -6300,6 +6330,11 @@ module OCamlbuildCommon = struct
else
[];
+ if bool_of_string (tests ()) then
+ ["-tag"; "tests"]
+ else
+ [];
+
if bool_of_string (profile ()) then
["-tag"; "profile"]
else
@@ -6615,7 +6650,7 @@ module OCamlbuildDocPlugin = struct
end
-# 6616 "setup.ml"
+# 6651 "setup.ml"
open OASISTypes;;
let setup_t =
@@ -6644,13 +6679,13 @@ let setup_t =
distclean_doc = [];
package =
{
- oasis_version = "0.3";
- ocaml_version = None;
+ oasis_version = "0.4";
+ ocaml_version = Some (OASISVersion.VGreaterEqual "3.12.0");
findlib_version = None;
alpha_features = [];
beta_features = [];
name = "benchmark";
- version = "1.3.1";
+ version = "1.4";
license =
OASISLicense.DEP5License
(OASISLicense.DEP5Unit
@@ -6661,7 +6696,8 @@ let setup_t =
});
license_file = None;
copyrights = [];
- maintainers = [];
+ maintainers =
+ ["Christophe Troestler <Christophe.Troestler@umons.ac.be>"];
authors =
["Christophe Troestler <Christophe.Troestler@umons.ac.be>"];
homepage = Some "http://ocaml-benchmark.forge.ocamlcore.org/";
@@ -7100,6 +7136,33 @@ let setup_t =
bs_nativeopt = [(OASISExpr.EBool true, [])]
},
{exec_custom = false; exec_main_is = "long_run.ml"});
+ Executable
+ ({
+ cs_name = "tree";
+ cs_data = PropList.Data.create ();
+ cs_plugin_data = []
+ },
+ {
+ bs_build =
+ [
+ (OASISExpr.EBool true, false);
+ (OASISExpr.EFlag "tests", true)
+ ];
+ bs_install = [(OASISExpr.EBool true, false)];
+ bs_path = "tests";
+ bs_compiled_object = Best;
+ bs_build_depends = [InternalLibrary "benchmark"];
+ bs_build_tools = [ExternalTool "ocamlbuild"];
+ bs_c_sources = [];
+ bs_data_files = [];
+ bs_ccopt = [(OASISExpr.EBool true, [])];
+ bs_cclib = [(OASISExpr.EBool true, [])];
+ bs_dlllib = [(OASISExpr.EBool true, [])];
+ bs_dllpath = [(OASISExpr.EBool true, [])];
+ bs_byteopt = [(OASISExpr.EBool true, [])];
+ bs_nativeopt = [(OASISExpr.EBool true, [])]
+ },
+ {exec_custom = false; exec_main_is = "tree.ml"});
SrcRepo
({
cs_name = "trunk";
@@ -7107,12 +7170,11 @@ let setup_t =
cs_plugin_data = []
},
{
- src_repo_type = Svn;
+ src_repo_type = Git;
src_repo_location =
- "svn://scm.ocamlcore.org/svn/ocaml-benchmark/trunk";
+ "https://github.com/Chris00/ocaml-benchmark.git";
src_repo_browser =
- Some
- "https://forge.ocamlcore.org/scm/browser.php?group_id=197";
+ Some "https://github.com/Chris00/ocaml-benchmark";
src_repo_module = None;
src_repo_branch = None;
src_repo_tag = None;
@@ -7125,8 +7187,9 @@ let setup_t =
plugin_data = []
};
oasis_fn = Some "_oasis";
- oasis_version = "0.4.4";
- oasis_digest = Some "\238n\184a\218\170\1476}\229\165m\203o\128M";
+ oasis_version = "0.4.5";
+ oasis_digest =
+ Some "\176\235\183tc\218(\254\224\132\024\180\239\152\198\242";
oasis_exec = None;
oasis_setup_args = [];
setup_update = false
@@ -7134,6 +7197,6 @@ let setup_t =
let setup () = BaseSetup.setup setup_t;;
-# 7136 "setup.ml"
+# 7199 "setup.ml"
(* OASIS_STOP *)
let () = setup ();;
diff --git a/tests/tree.ml b/tests/tree.ml
new file mode 100644
index 0000000..52ee2eb
--- /dev/null
+++ b/tests/tree.ml
@@ -0,0 +1,22 @@
+let () =
+ let open Benchmark.Tree in
+ "" @> lazy (let create() = Array.init 1_000_000 (fun i -> i) in
+ Benchmark.latency1 18L create () )
+ |> register;
+
+ "map" @> lazy (let a = Array.init 1_000_000 (fun i -> i) in
+ let f x = x + 1 in
+ Benchmark.latency1 18L (Array.map f) a )
+ |> register;
+
+ "sort"
+ @> lazy (let a = Array.init 1_000_000 (fun i -> -i) in
+ Benchmark.latency1 18L (Array.sort compare) a )
+ |> register;
+
+ "sort.add"
+ @> lazy (Benchmark.latency1 18L (fun x -> x + 1) 1)
+ |> register
+
+let () =
+ Benchmark.Tree.run_global ()