Commits

Yit Phang Khoo committed eb8845d Merge

Merge.

Comments (0)

Files changed (9)

+4f8799b5895174ff1e0b6be23b1d74f66d0473a3 PLDI 2014 AEC
+4f8799b5895174ff1e0b6be23b1d74f66d0473a3 PLDI 2014 AEC

Applications/As2/As2/Global.ml

 
   ("--repl",              Arg.Unit begin fun _ -> func := F_repl end, " functionality/mode: read-eval-print-loop (REPL)") ;
 
-  ("--stats-test",        Arg.Int begin fun n -> num_sheets := n; func := F_stats_test (n, `No_switch) end, " functionality/mode: run a predefined script, of a given size and record statisitics") ;
-  ("--stats-test-switch", Arg.Int begin fun n -> num_sheets := n; func := F_stats_test (n, `Switch) end,    " functionality/mode: run a predefined script (that switches), of a given size and record statisitics") ;
+  ("--stats-test",        Arg.Int begin fun n -> num_sheets := n; func := F_stats_test (n, `No_switch) end, " controls functionality/mode: run a predefined script, of a given size and record statisitics") ;
+(*  ("--stats-test-switch", Arg.Int begin fun n -> num_sheets := n; func := F_stats_test (n, `Switch) end,    " functionality/mode: run a predefined script (that switches), of a given size and record statisitics") ; *)
   ("--num-sheets",        Arg.Int begin fun i -> num_sheets := i end, " set the total number of sheets (default: 20)" ) ;
-  ("--num-changes",       Arg.Int begin fun i -> num_changes := i end, " set the number changes in the test script") ;
+  ("--num-changes",       Arg.Int begin fun i -> num_changes := i end, " set the number changes in the test script (default: 10)") ;
   ("--stats-out",         Arg.String begin fun s -> stats_out := s end, " write out stats to the given file" ) ;
 
   ("--Random.self_init", Arg.Unit begin fun _ -> Random.self_init () end, " initialize the Random module's number generator" ) ;

Applications/As2/As2/Main.ml

     ps "=========================================================================\n" ;
     ps "AS2 HELP:                                                                \n" ;
     ps "-------------------------------------------------------------------------\n" ;
-    ps "Commands:                                                                \n" ;
-    ps " 'help'            -- this help                                          \n" ;
-    ps " 'exit'            -- use excel instead                                  \n" ;
-    ps "                                                                         \n" ;
-    ps " = frm .           -- set formula of current cell to frm                 \n" ;
-    ps "                      Note: start with equals; terminate with a dot.     \n" ;
-    ps "                                                                         \n" ;
-    ps " 'goto' coord      -- goto a specific (sheet), row and column            \n" ;
-    ps " 'next' nav-thing  -- next col/row/sheet                                 \n" ;
-    ps " 'prev' nav-thing  -- prev col/row/sheet                                 \n" ;
+    ps " Note 1: all keywords, below in quotes, are also valid in all caps       \n" ;
+    ps " Note 2: all commands are terminated with a period                       \n" ;
+    ps "-------------------------------------------------------------------------\n" ;
+(*    ps "                                                                         \n" ; *)
+    ps "Command syntax                                                           \n" ;
+    ps " cmd ::=                                                                 \n" ;
+    ps " | 'help'               -- this help                                     \n" ;
+    ps " | 'exit'               -- use excel instead                             \n" ;
+(*    ps "                                                                         \n" ; *)
+    ps " | = frm                -- set formula of current cell to frm            \n" ;
+    ps " | 'print'              -- print the current sheet                       \n" ;
+(*    ps "                                                                         \n" ; *)
+    ps " | 'goto' coord         -- goto a specific (sheet), row and column       \n" ;
+    ps " | 'next' nav-thing     -- next col/row/sheet                            \n" ;
+    ps " | 'prev' nav-thing     -- prev col/row/sheet                            \n" ;
+(*    ps "                                                                         \n" ; *)
+    ps " | cmd1 ; cmd2          -- command sequencing                            \n" ;
+    ps " | 'repeat' n 'do' cmd  -- repeat a command n times                      \n" ;
     ps "                                                                         \n" ;
     ps "-------------------------------------------------------------------------\n" ;
     ps "Formula & Coordinate Syntax                                              \n" ;
     ps " Local coord  lc        ::= letters num                                  \n" ;
     ps " Local region lr        ::= lc : lc                                      \n" ;
     ps "-------------------------------------------------------------------------\n" ;
-    ps " All keywords, above in quotes, are also valid in all caps               \n" ;
-    ps "-------------------------------------------------------------------------\n" ;
     ()
 
   let parse_channel : string -> in_channel -> Ast.cmd =
               )
     in
     let _, m = measure (fun _ -> eval_cmd cmd cur) in
-    let out = open_out_gen [Open_append] 0 (!Global.stats_out) in
+    let out = open_out_gen [Open_creat;Open_append] 0 (!Global.stats_out) in
     output_string out (Printf.sprintf "%d, %d, %f, %d, %d, %d, %d, %d, %d\n"
                          sht_to_demand
                          num_changes

Benchmarks/BenchmarkAdapton/runbenchmarkadapton.ml

 let opt_task = ref "filter"
 let opt_input_size = ref 1
 let opt_repeat_count = ref 1
+let opt_take_count = ref 1
 let opt_edit_count = ref 1
-let opt_take_count = ref 1
+let opt_monotonic = ref false
 let opt_random_seed = ref 1
-let opt_monotonic = ref false
 
 let header ff = Printf.fprintf ff "%24s %24s %8d %8d %20d" !opt_a !opt_task !opt_take_count !opt_input_size !opt_random_seed
+let config ff =
+    Printf.fprintf ff "\"module\":\"%s\",\"task\":\"%s\",\"size\":%d,\"repeat\":%d,\"take\":%d,\"edit\":%d,\"monotonic\":%b,\"seed\":%d"
+        !opt_a !opt_task !opt_input_size !opt_repeat_count !opt_take_count !opt_edit_count !opt_monotonic !opt_random_seed
 let stats ff s =
-    Printf.fprintf ff "\"time\": %.17g, \"heap\": %.17g, \"stack\": %.17g, \"update\": %.17g, \"evaluate\": %.17g, \"dirty\": %.17g, \"clean\": %.17g"
+    Printf.fprintf ff "\"time\":%.17g,\"heap\":%d,\"stack\":%d,\"update\":%d,\"evaluate\":%d,\"dirty\":%d,\"clean\":%d"
         s.time s.heap s.stack s.update s.evaluate s.dirty s.clean
-let max_heap_stack ff ( heap, stack ) = Printf.fprintf ff "\"max-heap\": %.17g, \"max-stack\": %.17g" (word_bytes heap) (word_bytes stack)
+let top_heap_stack ff ( heap, stack ) = Printf.fprintf ff "\"max-heap\":%d,\"max-stack\":%d" (word_bytes heap) (word_bytes stack)
 let units =
-    "\"units\": { \"time\": \"seconds\", \"heap\": \"bytes\", \"stack\": \"bytes\", "
-    ^ "\"update\": null, \"evaluate\": null, \"dirty\": null, \"clean\": null, "
-    ^ "\"max-heap\": \"bytes\", \"max-stack\": \"bytes\" }"
+    "\"units\":{\"time\":\"seconds\",\"heap\":\"bytes\",\"stack\":\"bytes\",\"update\":null,\"evaluate\":null,\"dirty\":null,\"clean\":null,\"max-heap\":\"bytes\",\"max-stack\":\"bytes\"}"
 
 let show_config () =
     let list_printer printer ff list =
-        ignore (List.fold_left (fun b x -> Printf.fprintf ff "%(%)%a" b printer x; ", ") "" list)
+        ignore (List.fold_left (fun b x -> Printf.fprintf ff "%(%)%a" b printer x; ",") "" list)
     in
     let task_printer ff task =
-        Printf.fprintf ff "{ \"name\": %S, \"take\": %S }"
+        Printf.fprintf ff "{\"name\":%S,\"take\":%S}"
             (fst task) (match snd task with `One _ -> "one" | `List _ -> "list" | `Flip _ -> "flip" | `ExpTree -> "exptree")
     in
-    Printf.printf "{ \"modules\": [ %a ], \"tasks\": [ %a ] }\n%!"
+    Printf.printf "{\"modules\":[%a],\"tasks\":[%a],%s}\n%!"
         (list_printer (fun ff -> Printf.fprintf ff "%S")) (fst (List.split AdaptonZoo.All.a_list))
-        (list_printer task_printer) tasks;
+        (list_printer task_printer) tasks
+        units;
     exit 0
 
+let do_benchmark (module A : AdaptonUtil.Signatures.AType) ~make_input ~setup ~do_edit =
+    A.tweak_gc ();
+    Gc.compact ();
+    let start_time = get_time () in
+
+    let input = make_input () in
+    Gc.compact ();
+
+    Printf.eprintf "%t\n%!" header;
+    try
+        let take, setup_stats = measure begin fun () ->
+            let take = setup input in
+            take ();
+            take
+        end in
+        let setup_top_heap_stack = get_top_heap_stack () in
+
+        if A.is_incremental then begin
+            let stats_file, stats_out = Filename.open_temp_file ~mode:[ Open_append; Open_binary ] "runbenchmarkadapton." ".stats" in
+            let stats_in = open_in_bin stats_file in
+            Unix.unlink stats_file;
+            let rec do_edits past n = if n == 0 then () else
+                let past =
+                    let now = get_time () in
+                    if now -. past < 20. then
+                        past
+                    else begin
+                        let heap, stack = get_top_heap_stack () in
+                        Printf.eprintf "%t edit %10d %9.2fMB %9.2fMB\n%!"
+                            header n (word_megabytes heap) (word_megabytes stack);
+                        now
+                    end
+                in
+                let update_stats, take_stats, edit_count = do_edit input (fun () -> A.refresh (); take ()) in
+
+                let edit_heap, edit_stack = get_top_heap_stack () in
+                output_value stats_out ( update_stats, take_stats, edit_count, edit_heap, edit_stack );
+
+                do_edits past (pred n)
+            in
+            do_edits 0. !opt_edit_count;
+            close_out stats_out;
+            let edit_time = ref 0. in
+            let stats_array = Array.init !opt_edit_count begin fun _ ->
+                let ( update_stats, take_stats, _, _, _ ) as stat = input_value stats_in in
+                edit_time := !edit_time +. update_stats.time +. take_stats.time;
+                stat
+            end in
+            close_in stats_in;
+            let print_stats_list fmt get ff =
+                Array.iteri begin fun k stat ->
+                    if k > 0 then output_string ff ",";
+                    Printf.fprintf ff fmt (get stat);
+                end stats_array;
+            in
+            let print_stats_lists get ff =
+                Printf.fprintf ff "\"time\":[%t],\"heap\":[%t],\"stack\":[%t],\"update\":[%t],\"evaluate\":[%t],\"dirty\":[%t],\"clean\":[%t]"
+                    (print_stats_list "%.17g" (fun x -> (get x).time))
+                    (print_stats_list "%d" (fun x -> (get x).heap))
+                    (print_stats_list "%d" (fun x -> (get x).stack))
+                    (print_stats_list "%d" (fun x -> (get x).update))
+                    (print_stats_list "%d" (fun x -> (get x).evaluate))
+                    (print_stats_list "%d" (fun x -> (get x).dirty))
+                    (print_stats_list "%d" (fun x -> (get x).clean))
+            in
+            Printf.printf "{%t,\"setup\":{%a,%a},\"edits\":{\"update\":{%t},\"take\":{%t},\"edit-count\":[%t],\"max-heap\":[%t],\"max-stack\":[%t]}}\n%!"
+                config stats setup_stats top_heap_stack setup_top_heap_stack
+                (print_stats_lists (fun ( u, _, _, _, _ ) -> u))
+                (print_stats_lists (fun ( _, t, _, _, _ ) -> t))
+                (print_stats_list "%d" (fun ( _, _, e, _, _ ) -> e))
+                (print_stats_list "%d" (fun ( _, _, _, h, _ ) -> word_bytes h))
+                (print_stats_list "%d" (fun ( _, _, _, _, s ) -> word_bytes s));
+            Printf.eprintf "%t ... done (%9.2fs) %9.3gs edit %9.3gs\n%!"
+                header (get_time () -. start_time) setup_stats.time !edit_time
+        end else begin
+            Printf.printf "{%t,\"setup\":{%a,%a}}\n%!"
+                config stats setup_stats top_heap_stack setup_top_heap_stack;
+            Printf.eprintf "%t ... done (%9.2fs) %9.3gs\n%!" header (get_time () -. start_time) setup_stats.time
+        end
+    with e ->
+        let err = Printexc.to_string e in
+        Printf.printf "{%t,\"error\":%S}\n%!" config err;
+        Printf.eprintf "%s\n%!" err;
+        Printf.eprintf "%t ... done (%9.2fs)\n%!" header (get_time () -. start_time)
+
 let exptree (module A : AdaptonUtil.Signatures.AType) rng =
     if !opt_input_size < 4 then begin
         Printf.eprintf "Task %s only supports -I n where n >= 4\n%!" !opt_task;
             | Op ( Div, x, y ) -> let y = F.force (eval y) in F.force (eval x) /. (if y == 0. then 1. else y)
         end
     end in
-    A.tweak_gc ();
-    Gc.compact ();
-    let start_time = get_time () in
+    let half = int_of_float (floor (log (float_of_int !opt_input_size) /. log 2. /. 2.)) in
 
-    let x =
+    let make_input () =
         let rec make_xs n acc = if n > 0 then
             make_xs (n - 1) (E.const (E.rand_num ())::acc)
         else
         make_xs !opt_input_size []
     in
 
-    Printf.eprintf "%t\n%!" header;
-    begin try
-        let take, setup_stats = measure begin fun () ->
-            let ys = Array.init !opt_repeat_count (fun _ -> E.eval x) in
-            let take () = Array.iter (fun y -> ignore (F.force y)) ys in
-            take ();
-            take
-        end in
-        let setup_stats = finish setup_stats 1 in
-        let setup_top_heap_stack = get_top_heap_stack () in
+    let setup x =
+        let ys = Array.init !opt_repeat_count (fun _ -> E.eval x) in
+        fun () -> Array.iter (fun y -> ignore (F.force y)) ys
+    in
 
-        if A.is_incremental then begin
-            let half = int_of_float (floor (log (float_of_int !opt_input_size) /. log 2. /. 2.)) in
-            let rec do_edits past n update_stats take_stats edit_count =
-                if n == 0 then
-                    ( update_stats, take_stats, edit_count )
-                else begin
-                    let past =
-                        let now = get_time () in
-                        if now -. past < 20. then
-                            past
-                        else begin
-                            let heap, stack = get_top_heap_stack () in
-                            Printf.eprintf "%t edit %10d %9.2fMB %9.2fMB\n%!"
-                                header n (word_megabytes heap) (word_megabytes stack);
-                            now
+    let do_edit = if !opt_monotonic then
+        begin fun x take ->
+            (* add/remove one leaf *)
+            let rec change add x = match E.force x with
+                | E.Op ( op, a, b ) ->
+                    let dir = Random.State.bool rng in
+                    let y = if dir then a else b in
+                    begin match E.force y with
+                        | E.Num _ as z ->
+                            if add then
+                                E.update_const y (E.rand_op (E.const z) (E.const (E.rand_num ())))
+                            else
+                                E.update_const x (E.force (if dir then b else a))
+                        | _ ->
+                            change add y
+                    end
+                | E.Num _ ->
+                    failwith "change"
+            in
+
+            let (), update_stats = measure (fun () -> change false x) in
+            let (), take_stats = measure take in
+            let (), update_stats' = measure (fun () -> change true x) in
+            let (), take_stats' = measure take in
+
+            ( add update_stats update_stats', add take_stats take_stats', 2 )
+        end
+    else
+        begin fun x take ->
+            (* swap two nodes *)
+            let rec pick n x =
+                if n == 0 then x else match E.force x with
+                    | E.Op ( op, a, b ) ->
+                        let dir = Random.State.bool rng in
+                        pick (n - 1) (if dir then a else b)
+                    | E.Num _ ->
+                        failwith "pick"
+            in
+            let a = pick half x in
+            let b =
+                let rec pick_b () = let b = pick half x in if b == a then pick_b () else b in
+                pick_b ()
+            in
+            let (), update_stats = measure begin fun () -> match E.force a, E.force b with
+                | E.Op ( aop, a1, a2 ), E.Op ( bop, b1, b2 ) ->
+                    if Random.State.bool rng then
+                        if Random.State.bool rng then begin
+                            E.update_const a (E.Op ( aop, a1, b1 ));
+                            E.update_const b (E.Op ( bop, a2, b2 ));
+                        end else begin
+                            E.update_const a (E.Op ( aop, b2, a2 ));
+                            E.update_const b (E.Op ( bop, b1, a1 ));
                         end
-                    in
+                    else
+                        if Random.State.bool rng then begin
+                            E.update_const a (E.Op ( aop, b1, a2 ));
+                            E.update_const b (E.Op ( bop, a1, b2 ));
+                        end else begin
+                            E.update_const a (E.Op ( aop, a1, b2 ));
+                            E.update_const b (E.Op ( bop, b1, a2 ));
+                        end
+                | _ ->
+                    failwith "swap"
+            end in
 
-                    let update_stats', take_stats', edit_count' = if !opt_monotonic then
-                        (* add/remove one leaf *)
-                        let rec change add x = match E.force x with
-                            | E.Op ( op, a, b ) ->
-                                let dir = Random.State.bool rng in
-                                let y = if dir then a else b in
-                                begin match E.force y with
-                                    | E.Num _ as z ->
-                                        if add then
-                                            E.update_const y (E.rand_op (E.const z) (E.const (E.rand_num ())))
-                                        else
-                                            E.update_const x (E.force (if dir then b else a))
-                                    | _ ->
-                                        change add y
-                                end
-                            | E.Num _ ->
-                                failwith "change"
-                        in
+            let (), take_stats = measure take in
 
-                        let (), update_stats = measure (fun () -> change false x) in
-                        let (), take_stats = measure (fun () -> A.refresh (); take ()) in
-                        let (), update_stats' = measure (fun () -> change true x) in
-                        let (), take_stats' = measure (fun () -> A.refresh (); take ()) in
+            ( update_stats, take_stats, 1 )
+        end
+    in
 
-                        ( add update_stats update_stats', add take_stats take_stats', 2 )
-                    else
-                        (* swap two nodes *)
-                        let rec pick n x =
-                            if n == 0 then x else match E.force x with
-                                | E.Op ( op, a, b ) ->
-                                    let dir = Random.State.bool rng in
-                                    pick (n - 1) (if dir then a else b)
-                                | E.Num _ ->
-                                    failwith "pick"
-                        in
-                        let a = pick half x in
-                        let b =
-                            let rec pick_b () = let b = pick half x in if b == a then pick_b () else b in
-                            pick_b ()
-                        in
-                        let (), update_stats = measure begin fun () -> match E.force a, E.force b with
-                            | E.Op ( aop, a1, a2 ), E.Op ( bop, b1, b2 ) ->
-                                if Random.State.bool rng then
-                                    if Random.State.bool rng then begin
-                                        E.update_const a (E.Op ( aop, a1, b1 ));
-                                        E.update_const b (E.Op ( bop, a2, b2 ));
-                                    end else begin
-                                        E.update_const a (E.Op ( aop, b2, a2 ));
-                                        E.update_const b (E.Op ( bop, b1, a1 ));
-                                    end
-                                else
-                                    if Random.State.bool rng then begin
-                                        E.update_const a (E.Op ( aop, b1, a2 ));
-                                        E.update_const b (E.Op ( bop, a1, b2 ));
-                                    end else begin
-                                        E.update_const a (E.Op ( aop, a1, b2 ));
-                                        E.update_const b (E.Op ( bop, b1, a2 ));
-                                    end
-                            | _ ->
-                                failwith "swap"
-                        end in
+    do_benchmark (module A) ~make_input ~setup ~do_edit
 
-                        let (), take_stats = measure (fun () -> A.refresh (); take ()) in
-
-                        ( update_stats, take_stats, 1 )
-                    in
-
-                    do_edits past (pred n)
-                        (add update_stats update_stats')
-                        (add take_stats take_stats')
-                        (edit_count + edit_count')
-                end
-            in
-            let update_stats, take_stats, edit_count = do_edits 0. !opt_edit_count zero zero 0 in
-            let edit_top_heap_stack = get_top_heap_stack () in
-            let update_stats = finish update_stats !opt_edit_count in
-            let take_stats = finish take_stats !opt_edit_count in
-            Printf.printf "{ \"setup\": { %a, %a }, \"edits\": { \"update\": { %a }, \"take\": { %a }, %a }, %s }\n%!"
-                stats setup_stats max_heap_stack setup_top_heap_stack stats update_stats stats take_stats max_heap_stack edit_top_heap_stack units;
-            Printf.eprintf "%t ... done (%9.2fs) %9.3gs edit %9.3gs\n%!"
-                header (get_time () -. start_time) setup_stats.time (update_stats.time +. take_stats.time)
-        end else begin
-            Printf.printf "{ \"setup\": { %a, %a }, %s }\n%!"
-                stats setup_stats max_heap_stack setup_top_heap_stack units;
-            Printf.eprintf "%t ... done (%9.2fs) %9.3gs\n%!" header (get_time () -. start_time) setup_stats.time
-        end
-
-    with e ->
-        let err = Printexc.to_string e in
-        Printf.printf ("{ \"error\": %S }\n%!") err;
-        Printf.eprintf "%s\n%!" err;
-        Printf.eprintf "%t ... done (%9.2fs)\n%!" header (get_time () -. start_time)
-    end;
-    exit 0
-
-let _ =
-    Arg.parse (Arg.align [
-        ( "-c", Arg.Unit show_config, " output available configuration" );
-        ( "-m", Arg.Symbol ( (fst (List.split AdaptonZoo.All.a_list)), (fun s -> opt_a := s) ), "list module" );
-        ( "-t", Arg.Symbol ( (fst (List.split tasks)), (fun s -> opt_task := s) ), "list task" );
-        ( "-I", Arg.Set_int opt_input_size, "size input size" );
-        ( "-R", Arg.Set_int opt_repeat_count, "count repeat count" );
-        ( "-T", Arg.Set_int opt_take_count, "count take count" );
-        ( "-E", Arg.Set_int opt_edit_count, "count edit count" );
-        ( "-S", Arg.Set_int opt_random_seed, "seed random seed" );
-        ( "-M", Arg.Set opt_monotonic, "monotonic edits" );
-    ]) (fun s -> raise (Arg.Bad ("extraneous argument " ^ s))) (Sys.argv.(0) ^ " [options]");
-
-    let rng = Random.State.make [| !opt_random_seed |] in
-    Random.init (Random.State.bits rng);
-    let module A = (val (List.assoc !opt_a AdaptonZoo.All.a_list)) in
-    begin match List.assoc !opt_task tasks with
-        | `ExpTree -> exptree (module A) rng
-        | _ -> ()
-    end;
+let listtasks (module A : AdaptonUtil.Signatures.AType) rng =
     let module ABool = A.Make (AdaptonUtil.Types.Bool) in
     let module AList = AdaptonUtil.AList.Make (A) in
     let module AFloatList = AList.Make (AdaptonUtil.Types.Float) in
-    A.tweak_gc ();
-    Gc.compact ();
+    let make_input () =
+        let xs = ref (AFloatList.const `Nil) in
+        let xss = Array.init !opt_input_size begin fun _ ->
+            xs := AFloatList.const (`Cons (Random.State.float rng 1.0, !xs));
+            !xs
+        end in
+        let xs = !xs in
+        let last = ref 0 in
+        let b = ABool.const false in
+        ( xs, xss, last, b )
+    in
+
     let task = match List.assoc !opt_task tasks with
         | `One task ->
             if !opt_take_count != 1 then begin
             failwith "exptree"
     in
 
-    let start_time = get_time () in
+    let setup = match task with
+        | `List task ->
+            fun ( xs, _, _, b ) ->
+                let yss = Array.init !opt_repeat_count (fun _ -> task xs) in
+                (fun () -> Array.iter (fun ys -> ignore (AFloatList.take ys !opt_take_count)) yss)
+        | `One task ->
+            fun ( xs, _, _, b ) ->
+                let ys = Array.init !opt_repeat_count (fun _ -> task xs) in
+                (fun () -> Array.iter (fun y -> ignore (AFloatList.AData.force y)) ys)
+        | `Flip task ->
+            fun ( xs, _, _, b ) ->
+                let yss = Array.init !opt_repeat_count (fun _ -> task xs b) in
+                (fun () -> Array.iter (fun ys -> ignore (AFloatList.take ys !opt_take_count)) yss)
+        | `ExpTree ->
+            failwith "exptree"
+    in
 
-    let xs = ref (AFloatList.const `Nil) in
-    let xss = Array.init !opt_input_size begin fun _ ->
-        xs := AFloatList.const (`Cons (Random.State.float rng 1.0, !xs));
-        !xs
-    end in
-    let xs = !xs in
-    let last = ref 0 in
+    let do_edit = match task with
+        | `List _ | `One _ when !opt_monotonic ->
+            fun ( xs, xss, last, b ) take ->
+                (* delete then re-insert *)
+                let edit = Random.State.int rng !opt_input_size in
+                let zs = xss.(edit) in
 
-    let b = ABool.const false in
+                let ( z', zs' ), delete_update_stats = measure begin fun () ->
+                    match AFloatList.force zs with
+                        | `Cons ( z', zs' ) ->
+                            AFloatList.update_const zs (AFloatList.force zs');
+                            ( z', zs' )
+                        | `Nil ->
+                            failwith "delete"
+                end in
 
-    Printf.eprintf "%t\n%!" header;
-    try
-        let take, setup_stats = measure begin fun () ->
-            let take = match task with
-                | `List task ->
-                    let yss = Array.init !opt_repeat_count (fun _ -> task xs) in
-                    (fun () -> Array.iter (fun ys -> ignore (AFloatList.take ys !opt_take_count)) yss)
-                | `One task ->
-                    let ys = Array.init !opt_repeat_count (fun _ -> task xs) in
-                    (fun () -> Array.iter (fun y -> ignore (AFloatList.AData.force y)) ys)
-                | `Flip task ->
-                    let yss = Array.init !opt_repeat_count (fun _ -> task xs b) in
-                    (fun () -> Array.iter (fun ys -> ignore (AFloatList.take ys !opt_take_count)) yss)
-                | `ExpTree ->
-                    failwith "exptree"
-            in
-            take ();
-            take
-        end in
-        let setup_stats = finish setup_stats 1 in
-        let setup_top_heap_stack = get_top_heap_stack () in
+                let (), delete_take_stats = measure take in
+                let (), insert_update_stats = measure (fun () -> AFloatList.update_const zs (`Cons ( z', zs' ))) in
+                let (), insert_take_stats = measure take in
 
-        if A.is_incremental then begin
-            let rec do_edits past n update_stats take_stats edit_count =
-                if n == 0 then
-                    ( update_stats, take_stats, edit_count )
-                else begin
-                    let past =
-                        let now = get_time () in
-                        if now -. past < 20. then
-                            past
-                        else begin
-                            let heap, stack = get_top_heap_stack () in
-                            Printf.eprintf "%t edit %10d %9.2fMB %9.2fMB %6.0fs left\n%!"
-                                header n (word_megabytes heap) (word_megabytes stack)
-                                (float_of_int n *. (get_time () -. start_time) /. float_of_int (!opt_edit_count - n));
-                            now
-                        end
-                    in
+                ( add delete_update_stats insert_update_stats, add delete_take_stats insert_take_stats, 2 )
 
-                    let update_stats', take_stats', edit_count' = match task with
-                        | `List _ | `One _ when !opt_monotonic ->
-                            (* delete then re-insert *)
-                            let edit = Random.State.int rng !opt_input_size in
-                            let zs = xss.(edit) in
+        | `List _ | `One _ ->
+            fun ( xs, xss, last, b ) take ->
+                (* split into two and swap *)
+                let edit = 1 + Random.State.int rng (!opt_input_size - 2) in
+                let edit = if edit = !last then edit + 1 else edit in
+                let zs = xss.(edit) in
 
-                            let ( z', zs' ), delete_update_stats = measure begin fun () ->
-                                match AFloatList.force zs with
-                                    | `Cons ( z', zs' ) ->
-                                        AFloatList.update_const zs (AFloatList.force zs');
-                                        ( z', zs' )
-                                    | `Nil ->
-                                        failwith "delete"
-                            end in
+                let (), update_stats = measure begin fun () ->
+                    match AFloatList.force xs with
+                        | `Cons _ as xs' ->
+                            begin match AFloatList.force xss.(!last) with
+                                | `Cons _ as last' ->
+                                    begin match AFloatList.force zs with
+                                        | `Cons _ as zs' ->
+                                            AFloatList.update_const xs zs';
+                                            AFloatList.update_const xss.(!last) xs';
+                                            AFloatList.update_const zs last';
+                                            last := edit;
+                                        | `Nil ->
+                                            failwith "swap"
+                                    end
+                                | `Nil ->
+                                    failwith "swap"
+                            end
+                        | `Nil ->
+                            failwith "swap"
+                end in
 
-                            let (), delete_take_stats = measure begin fun () ->
-                                A.refresh ();
-                                take ()
-                            end in
+                let (), take_stats = measure take in
 
-                            let (), insert_update_stats = measure begin fun () ->
-                                AFloatList.update_const zs (`Cons ( z', zs' ))
-                            end in
+                ( update_stats, take_stats, 1 )
 
-                            let (), insert_take_stats = measure begin fun () ->
-                                A.refresh ();
-                                take ()
-                            end in
+        | `Flip _ ->
+            fun ( xs, xss, last, b ) take ->
+                (* change one value *)
+                let edit = Random.State.int rng !opt_input_size in
+                let value = Random.State.float rng 1.0 in
+                let zs = xss.(edit) in
 
-                            ( add delete_update_stats insert_update_stats, add delete_take_stats insert_take_stats, 2 )
+                let (), update_stats = measure begin fun () ->
+                    ABool.update_const b (not (ABool.force b));
+                    match AFloatList.force zs with
+                        | `Cons ( _, zs' ) ->
+                            AFloatList.update_const zs (`Cons ( value, zs' ))
+                        | `Nil ->
+                            failwith "flip"
+                end in
 
-                        | `List _ | `One _ ->
-                            (* split into two and swap *)
-                            let edit = 1 + Random.State.int rng (!opt_input_size - 2) in
-                            let edit = if edit = !last then edit + 1 else edit in
-                            let zs = xss.(edit) in
+                let (), take_stats = measure take in
+                let (), update_stats' = measure (fun () -> ABool.update_const b (not (ABool.force b))) in
+                let (), take_stats' = measure take in
 
-                            let (), update_stats = measure begin fun () ->
-                                match AFloatList.force xs with
-                                    | `Cons _ as xs' ->
-                                        begin match AFloatList.force xss.(!last) with
-                                            | `Cons _ as last' ->
-                                                begin match AFloatList.force zs with
-                                                    | `Cons _ as zs' ->
-                                                        AFloatList.update_const xs zs';
-                                                        AFloatList.update_const xss.(!last) xs';
-                                                        AFloatList.update_const zs last';
-                                                        last := edit;
-                                                    | `Nil ->
-                                                        failwith "swap"
-                                                end
-                                            | `Nil ->
-                                                failwith "swap"
-                                        end
-                                    | `Nil ->
-                                        failwith "swap"
-                            end in
+                ( add update_stats update_stats', add take_stats take_stats', 2 )
 
-                            let (), take_stats = measure begin fun () ->
-                                A.refresh ();
-                                take ()
-                            end in
+        | `ExpTree ->
+            failwith "exptree"
+    in
 
-                            ( update_stats, take_stats, 1 )
+    do_benchmark (module A) ~make_input ~setup ~do_edit
 
-                        | `Flip _ ->
-                            (* change one value *)
-                            let edit = Random.State.int rng !opt_input_size in
-                            let value = Random.State.float rng 1.0 in
-                            let zs = xss.(edit) in
+let _ =
+    Arg.parse (Arg.align [
+        ( "-c", Arg.Unit show_config, " output available configuration" );
+        ( "-m", Arg.Symbol ( (fst (List.split AdaptonZoo.All.a_list)), (fun s -> opt_a := s) ), "list module" );
+        ( "-t", Arg.Symbol ( (fst (List.split tasks)), (fun s -> opt_task := s) ), "list task" );
+        ( "-I", Arg.Set_int opt_input_size, "size input size" );
+        ( "-R", Arg.Set_int opt_repeat_count, "count repeat count" );
+        ( "-T", Arg.Set_int opt_take_count, "count take count" );
+        ( "-E", Arg.Set_int opt_edit_count, "count edit count" );
+        ( "-M", Arg.Set opt_monotonic, "monotonic edits" );
+        ( "-S", Arg.Set_int opt_random_seed, "seed random seed" );
+    ]) (fun s -> raise (Arg.Bad ("extraneous argument " ^ s))) (Sys.argv.(0) ^ " [options]");
 
-                            let (), update_stats = measure begin fun () ->
-                                ABool.update_const b (not (ABool.force b));
-                                match AFloatList.force zs with
-                                    | `Cons ( _, zs' ) ->
-                                        AFloatList.update_const zs (`Cons ( value, zs' ))
-                                    | `Nil ->
-                                        failwith "flip"
-                            end in
-
-                            let (), take_stats = measure (fun () -> A.refresh (); take ()) in
-                            let (), update_stats' = measure (fun () -> ABool.update_const b (not (ABool.force b))) in
-                            let (), take_stats' = measure (fun () -> A.refresh (); take ()) in
-
-                            ( add update_stats update_stats', add take_stats take_stats', 2 )
-
-                        | `ExpTree ->
-                            failwith "exptree"
-                    in
-
-                    do_edits past (pred n)
-                        (add update_stats update_stats')
-                        (add take_stats take_stats')
-                        (edit_count + edit_count')
-                end
-            in
-            let update_stats, take_stats, edit_count = do_edits 0. !opt_edit_count zero zero 0 in
-            let edit_top_heap_stack = get_top_heap_stack () in
-            let update_stats = finish update_stats edit_count in
-            let take_stats = finish take_stats edit_count in
-            Printf.printf "{ \"setup\": { %a, %a }, \"edits\": { \"update\": { %a }, \"take\": { %a }, %a }, %s }\n%!"
-                stats setup_stats max_heap_stack setup_top_heap_stack stats update_stats stats take_stats max_heap_stack edit_top_heap_stack units;
-            Printf.eprintf "%t ... done (%9.2fs) %9.3gs edit %9.3gs\n%!"
-                header (get_time () -. start_time) setup_stats.time (update_stats.time +. take_stats.time)
-        end else begin
-            Printf.printf "{ \"setup\": { %a, %a }, %s }\n%!"
-                stats setup_stats max_heap_stack setup_top_heap_stack units;
-            Printf.eprintf "%t ... done (%9.2fs) %9.3gs\n%!" header (get_time () -. start_time) setup_stats.time
-        end
-
-    with e ->
-        let err = Printexc.to_string e in
-        Printf.printf ("{ \"error\": %S }\n%!") err;
-        Printf.eprintf "%s\n%!" err;
-        Printf.eprintf "%t ... done (%9.2fs)\n%!" header (get_time () -. start_time)
+    let rng = Random.State.make [| !opt_random_seed |] in
+    Random.init (Random.State.bits rng);
+    let module A = (val (List.assoc !opt_a AdaptonZoo.All.a_list)) in
+    match List.assoc !opt_task tasks with
+        | `ExpTree -> exptree (module A) rng
+        | _ -> listtasks (module A) rng

Benchmarks/BenchmarkAdapton/runbenchmarkadapton.py

 def driver(( module, task, size, repeat, take, edit, monotonic, seed )):
     driver_start_time = time.time()
     rng = random.Random(seed)
-    results = OrderedDict((
-        ( "module", module ), ( "task", task ),
-        ( "size", size ), ( "repeat", repeat), ( "take", take ), ( "edit", edit ), ( "monotonic", monotonic ),
-        ( "seed", seed ) ))
     try:
-        cmd = [ runbenchmarkadapton_native, "-m", "%s" % ( module, ), "-t", str(task), "-I", str(size), "-R", str(repeat), "-T", str(take), "-E", str(edit) ]
+        cmd = [ runbenchmarkadapton_native, "-m", str(module), "-t", str(task), "-I", str(size), "-R", str(repeat), "-T", str(take), "-E", str(edit) ]
         if monotonic:
             cmd.append("-M")
         cmd.extend(( "-S", str(seed) ))
         native = subprocess.Popen(cmd, stdout=subprocess.PIPE, env={ "BENCHMARK_SALIST_ENV": " " * rng.randrange(4096) })
-        results.update(json.load(native.stdout, object_pairs_hook=OrderedDict))
-        return results
+        return native.stdout.read()
 
     except Exception, KeyboardInterrupt:
         error = traceback.format_exc()
-        results["error"] = error
         print>>sys.stderr, error
         print>>sys.stderr, "%32s %24s %4d %10d %20d ... error (%9.2fs)" % ( module, task, take, size, seed, time.time() - driver_start_time )
-        return results
+        return json.dumps(OrderedDict((
+            ( "module", module ), ( "task", task ),
+            ( "size", size ), ( "repeat", repeat), ( "take", take ), ( "edit", edit ), ( "monotonic", monotonic ),
+            ( "seed", seed ), ( "error", error ) )))
     finally:
         try:
             native.kill()
         import re
         re_lscpu = re.compile(r"Core\(s\) per socket:\s+([0-9]+).*Socket\(s\):\s+([0-9]+)", re.MULTILINE | re.DOTALL)
         try:
-            m = re_lscpu.find(subprocess.check_output("lscpu"))
+            m = re_lscpu.search(subprocess.check_output("lscpu"))
         except Exception:
             cpu_count = 0
         else:
             if m:
-                cpu_count = int(m.group(1) * m.group(2))
+                cpu_count = int(m.group(1)) * int(m.group(2))
             else:
                 cpu_count = 0
         if cpu_count == 0:
 
 
 if __name__ == "__main__":
-    import argparse, errno, gzip, multiprocessing, pprint, re, urllib
+    import argparse, errno, gzip, multiprocessing, re, urllib
+    from pprint import pprint, pformat
 
     config = json.loads(subprocess.check_output([ runbenchmarkadapton_native, "-c" ]))
     config["modules"] = map(str, config["modules"])
                 finally:
                     if len(args.input_sizes) > 1:
                         assert len(args.take_counts) == 1
-                        results = OrderedDict((
-                            ( "label", "take count = %d" % ( args.take_counts[0], ) ),
-                            ( "x-axis", "size" ),
-                            ( "x-label", "input size" ),
-                            ( "data", results )
-                        ))
+                        label = "take count = %d" % ( args.take_counts[0], )
+                        x_axis = "size"
+                        x_label = "input size"
                     elif len(args.take_counts) > 1:
                         assert len(args.input_sizes) == 1
-                        results = OrderedDict((
-                            ( "label", "input size = %d" % ( args.input_sizes[0], ) ),
-                            ( "x-axis", "take" ),
-                            ( "x-label", "take count" ),
-                            ( "data", results )
-                        ))
+                        label = "input size = %d" % ( args.input_sizes[0], )
+                        x_axis = "take"
+                        x_label = "take count"
                     else:
                         assert len(args.take_counts) == 1 and len(args.input_sizes) == 1
-                        results = OrderedDict((
-                            ( "label", "input size = %d; count = %d" % ( args.input_sizes[0], args.take_counts[0] ) ),
-                            ( "x-axis", "size" ),
-                            ( "x-label", "" ),
-                            ( "data", results )
-                        ))
+                        label = "input size = %d; count = %d" % ( args.input_sizes[0], args.take_counts[0] )
+                        x_axis = "size"
+                        x_label = ""
                     with gzip.open(os.path.join(output, "%s-%04d.json.gz" % ( task, len(results) )), "w") as jsonfile:
-                        json.dump(results, jsonfile, indent=4, separators=( ",", ":" ))
+                        print>>jsonfile, "{\"units\":%s,\"label\":\"%s\",\"x-axis\":\"%s\",\"x-label\":\"%s\",\"data\":[%s]}" \
+                            % ( json.dumps(config["units"]), label, x_axis, x_label, ", ".join(results) )
 
     if not args.summaries:
         sys.exit()
 
         with Tee(sys.stderr, os.path.join(output, "summary.txt"), "w") as txtfile:
             tasks = OrderedDict()
-            units = {}
             editables = set()
             for file in files:
                 label = file[:-13]
                         if not results:
                             results = more_results
                         else:
+                            if more_results["units"] != results["units"]:
+                                raise ValueError("inconsistent units in results:\nexpected: %s\ngot: %s" % ( pformat(results["units"]), pformat(more_results["units"]) ))
                             if more_results["label"] != results["label"]:
                                 raise ValueError("inconsistent label in results:\nexpected: %s\ngot: %s" % ( results["label"], more_results["label"] ))
                             if more_results["x-axis"] != results["x-axis"]:
                                 .setdefault(record[results["x-axis"]], []).append(record["setup"][key])
                             sizes.add(record["size"])
                             takes.add(record["take"])
-                        if not units:
-                            units = record["units"]
-                        elif units != record["units"]:
-                            raise ValueError("inconsistent units in results:\nexpected: %s\ngot: %s" % ( pprint.pformat(units), pprint.pformat(record["units"]) ))
                     except Exception:
                         traceback.print_exc()
                         if "error" in record:
-                            pprint.pprint(dict(record))
+                            pprint(dict(record))
                     else:
                         if "edits" in record:
                             editables.add(record["module"])
                             try:
+                                edit_count = float(sum(record["edits"]["edit-count"]))
                                 for key in table.iterkeys():
                                     if key.startswith("max-"):
                                         table[key].setdefault("propagate", {}).setdefault(record["module"], {}) \
-                                            .setdefault(record[results["x-axis"]], []).append(record["edits"][key])
+                                            .setdefault(record[results["x-axis"]], []).append(record["edits"][key][-1])
                                     else:
+                                        update = sum(record["edits"]["update"][key]) / edit_count
+                                        take = sum(record["edits"]["take"][key]) / edit_count
                                         table[key].setdefault("propagate", {}).setdefault(record["module"], {}) \
-                                            .setdefault(record[results["x-axis"]], []).append(record["edits"]["update"][key] + record["edits"]["take"][key])
+                                            .setdefault(record[results["x-axis"]], []).append(update + take)
                                         table[key].setdefault("update", {}).setdefault(record["module"], {}) \
-                                            .setdefault(record[results["x-axis"]], []).append(record["edits"]["update"][key])
+                                            .setdefault(record[results["x-axis"]], []).append(update)
                             except Exception:
                                 traceback.print_exc()
                                 if "error" in record:
-                                    pprint.pprint(dict(record))
+                                    pprint(dict(record))
 
                 ymax = {}
                 for measurement, measurement_table in table.iteritems():
                         for baseline in args.baselines:
                             htmltable.th(baseline, colspan=2)
                         for editable in editables:
-                            htmltable.th(editable, colspan=2 * (len(args.baselines) + 1))
+                            htmltable.th(editable, colspan=2 * (len(args.baselines) + 2))
                     with htmltable.tr():
                         for _ in args.baselines:
                             htmltable.th("time", rowspan=2)
                             htmltable.th("max-heap", rowspan=2)
                         for _ in editables:
-                            htmltable.th("from-scratch", colspan=len(args.baselines) + 1)
-                            htmltable.th("incremental", colspan=len(args.baselines) + 1)
+                            htmltable.th("from-scratch", colspan=len(args.baselines) + 2)
+                            htmltable.th("incremental", colspan=len(args.baselines) + 2)
                     with htmltable.tr():
                         for _ in editables:
+                            htmltable.th("time")
                             htmltable.th("overhead", colspan=len(args.baselines))
                             htmltable.th("max-heap")
+                            htmltable.th("time")
                             htmltable.th("speed-up", colspan=len(args.baselines))
                             htmltable.th("max-heap")
                     with htmltable.tr():
                         for _ in args.baselines:
-                            htmltable.th(units["time"])
-                            htmltable.th(units["max-heap"])
+                            htmltable.th(results["units"]["time"])
+                            htmltable.th(results["units"]["max-heap"])
                         for _ in xrange(len(editables) * 2):
+                            htmltable.th(results["units"]["time"])
                             for baseline in args.baselines:
                                 htmltable.th(baseline)
-                            htmltable.th(units["max-heap"])
+                            htmltable.th(results["units"]["max-heap"])
                 engFormatter = EngFormatter(exp0=True)
                 with htmltable.tbody():
                     for label, task in tasks.iteritems():
                                 max_heap = table["max-heap"]["propagate"][editable].values()[-1]
                                 best["max-heap"] = min(max_heap, best.get("max-heap", max_heap))
                             for editable in editables:
+                                htmltable.td(engFormatter(table["time"]["from-scratch"][editable].values()[-1]))
                                 for baseline in args.baselines:
                                     overhead = performance[editable][baseline][0]
                                     htmltable.td(engFormatter(overhead))
                                 max_heap = table["max-heap"]["from-scratch"][editable].values()[-1]
                                 htmltable.td(engFormatter(max_heap))
+                                htmltable.td(engFormatter(table["time"]["propagate"][editable].values()[-1]))
                                 for baseline in args.baselines:
                                     speedup = performance[editable][baseline][1]
                                     htmltable.td(engFormatter(speedup), cls="" if speedup != best[baseline] else "highlight")
                                 ax = fig.add_subplot(1, 1, 1)
                                 ax.set_title(results["label"], fontsize=8)
                                 ax.set_xlabel(results["x-label"], fontsize=8)
-                                if units[measurement]:
-                                    ax.set_ylabel("%s (%s)" % ( measurement, units[measurement] ), fontsize=8)
+                                if results["units"][measurement]:
+                                    ax.set_ylabel("%s (%s)" % ( measurement, results["units"][measurement] ), fontsize=8)
                                 else:
                                     ax.set_ylabel("%s" % ( measurement, ), fontsize=8)
                                 for axis in ( ax.get_xaxis(), ax.get_yaxis() ):
                                 ax = fig.add_subplot(1, 1, 1)
                                 ax.set_title("%s details; %s" % ( module, results["label"] ), fontsize=8)
                                 ax.set_xlabel(results["x-label"], fontsize=8)
-                                ax.set_ylabel("time (%s)" % ( units["time"], ), fontsize=8)
+                                ax.set_ylabel("time (%s)" % ( results["units"]["time"], ), fontsize=8)
                                 for axis in ( ax.get_xaxis(), ax.get_yaxis() ):
                                     axis.set_major_formatter(EngFormatter())
                                     axis.set_ticks_position("none")
 
 .PRECIOUS : $(OCAMLBUILD_PRODUCTDIR)/runbenchmark%.py
 
-$(OCAMLBUILD_PRODUCTDIR)/runbenchmark%.py : runbenchmark%.py
+$(OCAMLBUILD_PRODUCTDIR)/runbenchmark%.py : runbenchmark%.py ocamlbuild//runbenchmark%.native
 	cp $< $@
 
-benchmark-% : check $(OCAMLBUILD_PRODUCTDIR)/runbenchmark%.py ocamlbuild//runbenchmark%.native
+benchmark-% : check $(OCAMLBUILD_PRODUCTDIR)/runbenchmark%.py
 	ulimit -s hard > /dev/null 2>&1 || ulimit -s unlimited; \
 		$(OCAMLBUILD_PRODUCTDIR)/runbenchmark$*.py benchmark \
 			$(and $(shell hg id 2>/dev/null),--label "r$(shell (hg id -n -rqparent && hg qapplied --config defaults.qapplied= || hg id -n) 2>/dev/null)") \
 
 4. Run Adapton.ocaml benchmarks:
 
-    * for systems with at least 8 cores and 16GB memory (runs up to 8 benchmarks in parallel)
+    * for systems with at least 8 cores and 16GB memory (runs up to 8 benchmarks in parallel; takes a good part of a
+      day)
 
             % make pldi2014-benchmarks
 
-    * for smaller systems with at least 1GB memory (similar to above except 10% of the input sizes, not run in parallel)
+    * for smaller systems with at least 1GB memory (similar to above except 10% of the input sizes, not run in parallel;
+      takes a couple of hours)
 
             % make small-pldi2014-benchmarks
 
-    * for the impatient (similar to above except 1% of the input sizes, not run in parallel)
+    * for the impatient (similar to above except 1% of the input sizes, not run in parallel; takes a few minutes)
 
             % make tiny-pldi2014-benchmarks
 
-    Note the larger benchmark will take a good part of a day to complete, whereas the smaller benchmark will take a few
-    hours, and the tiny benchmark takes a few minutes. Results will be written to
-    `Results/BenchmarkAdapton/*pldi2014-benchmarks-*/{lazy,batch,swap,switch}/summary` for a HTML or text summary of the
-    results, in particular, look under the _incremental_ columns:
+    Results will be written to `Results/BenchmarkAdapton/*pldi2014-benchmarks-*/{lazy,batch,swap,switch}/summary` as
+    HTML as well as text-only tables. In particular, look under the _incremental_ columns, e.g.:
 
                                     Adapton |                         EagerTotalOrder
                                 incremental |                             incremental
 
     Cells marked `*` show the highest speed-up over *NonInc or smallest memory usage.
 
+5. Run Adapton SpreadSheet (AS2) application:
+
+   * To run the native binary for the application interactively:
+
+            % ./_product/runas2.native
+
+     The interactive command "help." (with terminating period) will
+     cause the system to display a summary of its other commands, and
+     its formula syntax.
+
+   * To see a summary of command-line options:
+
+            % ./_product/runas2.native --help
+
+   * The application offers different implementations of the Adapton
+     primitives for comparison purposes. The command line switch
+     --adapton-module controls which implementation is used:
+
+            % ./_product/runas2.native --adapton-module <impl>
+
+     Where <impl> is one of:
+            * Adapton (this is the default)
+            * EagerTotalOrder
+            * EagerNonInc
+            * LazyNonInc
+
+  * The following test script works for all versions, and can be
+    entered interactively:
+
+        scrambled; goto 10!a1 ; print ; repeat 5 do scramble1 ; print done .
+
+  * Alternatively, this script can be invoked at the command-line as follows:
+
+        % ./_product/runas2.native --num-changes 5 --stats-test 10
+
+    In this mode, the program prints statistics and appends this
+    information to the file as2-stats.out, then exits.  The numbers 5
+    and 10 control the number of changes and total number of sheets,
+    respectively.  Of course, they can be changed to other integers.
+
 
 Requirements
 ============

Source/AdaptonUtil/Statistics.ml

 
 let word_size = Sys.word_size / 8
 
-let word_bytes words = float_of_int (word_size * words)
+let word_bytes words = word_size * words
 
-let word_megabytes words = word_bytes words /. 1048576.
+let word_megabytes words = float_of_int (word_bytes words) /. 1048576.
 
 let get_time = Unix.gettimeofday
 
 
 type t = {
     time : float; (** Elapsed time in seconds. *)
-    heap : float; (** Max heap delta in bytes. *)
-    stack : float; (** Max stack delta in bytes. *)
-    update : float; (** Thunks updated. *)
-    evaluate : float; (** Thunks re-evaluated. *)
-    dirty : float; (** For {!Adapton}, dependencies to be checked; for {!EagerTotalOrder}, thunks scheduled for re-evaluation. *)
-    clean : float; (** For {!Adapton}, dependencies checked clean; for {!EagerTotalOrder}, thunks unscheduled for re-evaluation (due to invalidation). *)
+    heap : int; (** Max heap delta in bytes. *)
+    stack : int; (** Max stack delta in bytes. *)
+    update : int; (** Thunks updated. *)
+    evaluate : int; (** Thunks re-evaluated. *)
+    dirty : int; (** For {!Adapton}, dependencies to be checked; for {!EagerTotalOrder}, thunks scheduled for re-evaluation. *)
+    clean : int; (** For {!Adapton}, dependencies checked clean; for {!EagerTotalOrder}, thunks unscheduled for re-evaluation (due to invalidation). *)
 }
 
-type u = {
-    time' : float;
-    heap' : int;
-    stack' : int;
-    update' : int;
-    evaluate' : int;
-    dirty' : int;
-    clean' : int;
-}
-
-let zero = { time'=0.; heap'=0; stack'=0; update'=0; evaluate'=0; dirty'=0; clean'=0 }
-
 let add s s' = {
-    time'=s.time' +. s'.time';
-    heap'=s.heap' + s'.heap';
-    stack'=s.stack' + s'.stack';
-    update'=s.update' + s'.update';
-    evaluate'=s.evaluate' + s'.evaluate';
-    dirty'=s.dirty' + s'.dirty';
-    clean'=s.clean' +s'.clean';
+    time=s.time +. s'.time;
+    heap=s.heap + s'.heap;
+    stack=s.stack + s'.stack;
+    update=s.update + s'.update;
+    evaluate=s.evaluate + s'.evaluate;
+    dirty=s.dirty + s'.dirty;
+    clean=s.clean +s'.clean;
 }
 
 let measure f =
     stack' := max stack !stack';
     let time = get_time () in
     let x = f () in
-    let time' = get_time () -. time in
+    let time = get_time () -. time in
     heap_stacks := old_heap_stacks;
     let measurement = {
-        time';
-        heap'=(!heap' - heap);
-        stack'=(!stack' - stack);
-        update'=(!Counts.update - update);
-        evaluate'=(!Counts.evaluate - evaluate);
-        dirty'=(!Counts.dirty - dirty);
-        clean'=(!Counts.clean - clean);
+        time;
+        heap=word_bytes (!heap' - heap);
+        stack=word_bytes (!stack' - stack);
+        update=(!Counts.update - update);
+        evaluate=(!Counts.evaluate - evaluate);
+        dirty=(!Counts.dirty - dirty);
+        clean=(!Counts.clean - clean);
     } in
     ( x, measurement )
-
-let finish s k =
-    let k = float_of_int k in {
-        time=s.time' /. k;
-        heap=word_bytes s.heap' /. k;
-        stack=word_bytes s.stack' /. k;
-        update=float_of_int s.update' /. k;
-        evaluate=float_of_int s.evaluate' /. k;
-        dirty=float_of_int s.dirty' /. k;
-        clean=float_of_int s.clean' /. k;
-    }
-<**/*.cm*> or <**/*.top> or <**/*.mli> or <**/*.native>: package(unix)
+<**/*.cm*> or <**/*.top> or <**/*.mli> or <**/*.native> or <**/*.byte>: package(unix)