-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathbench_exc.ml
129 lines (94 loc) · 2.75 KB
/
bench_exc.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
(*
A benchmark of delimcc: comparing abort with native OCaml exceptions
The benchmark times raising an exception that unwinds a large portion
of the stack. We compute the product of the list of numbers, throwing exception
upon encountering 0. For benchmarking purposes, we intentionally use
non-tail-recursive product computation, and make sure 0 occurs at the very end
of the list.
*)
open Delimcc;;
(* Make the list for the benchmark: all ones with 0 at the end *)
let make_test_data n =
let rec loop acc = function
| 0 -> List.rev (0::acc)
| n -> loop (1::acc) (pred n)
in loop [] n;;
exception Zero
let test1_ex lst =
let f x acc = if x = 0 then raise Zero else x * acc
in
try List.fold_right f lst 1 with Zero -> 0
;;
let 6 = test1_ex [1;2;3];;
let 0 = test1_ex [1;2;0;3];;
let test1_abort lst =
let p = new_prompt () in
let f x acc = if x = 0 then abort p 0 else x * acc
in
push_prompt p (fun () -> List.fold_right f lst 1)
;;
let 6 = test1_abort [1;2;3];;
let 0 = test1_abort [1;2;0;3];;
exception Other
(* Testing throwing an exception in the presence of many irrelevant handlers*)
let test2_ex lst =
let f x acc = if x = 0 then raise Zero else x * acc in
let rec loop acc = function
| [] -> acc
| h::t -> try f h (loop acc t) with Other -> -1
in
try loop 1 lst with Zero -> 0
;;
let 6 = test2_ex [1;2;3];;
let 0 = test2_ex [1;2;0;3];;
let test2_abort lst =
let p = new_prompt () in
let p' = new_prompt () in
let f x acc = if x = 0 then abort p 0 else x * acc in
let rec loop acc = function
| [] -> acc
| h::t -> push_prompt p' (fun () -> f h (loop acc t))
in
push_prompt p (fun () -> List.fold_right f lst 1)
;;
let 6 = test2_abort [1;2;3];;
let 0 = test2_abort [1;2;0;3];;
(* Running the benchmark *)
(* Time the execution *)
let timeit thunk =
let time_start = Sys.time () in
let r = thunk () in
Printf.printf "\nTime spent: %g sec\n" (Sys.time () -. time_start);
r;;
let bench testf =
for i = 1 to 5 do
timeit (fun () ->
Printf.printf "result: %d\n" (testf ()))
done
;;
(* A longer list causes stack overflow *)
let () =
Printf.printf "test1_ex\n\n";
bench (fun () -> test1_ex (make_test_data 110000));;
let () =
Printf.printf "test1_abort\n\n";
bench (fun () -> test1_abort (make_test_data 110000));;
let () =
Printf.printf "test2_ex\n\n";
bench (fun () -> test2_ex (make_test_data 110000));;
let () =
Printf.printf "test2_abort\n\n";
bench (fun () -> test2_abort (make_test_data 110000));;
(* The median result of 5 runs:
OCaml 3.12
Bytecode:
test1_ex: 0.055 sec
test1_abort: 0.051 sec
test2_ex: 0.056 sec
test2_abort: 0.054 sec
Native code:
test1_ex: 0.039 sec
test1_abort: 0.037 sec
test2_ex: 0.042 sec
test2_abort: 0.039 sec
*)