-
Notifications
You must be signed in to change notification settings - Fork 6
/
linear.ml
130 lines (120 loc) · 3.75 KB
/
linear.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
130
open! Core
open! Import
type sequence_kind =
| Trivial
| Recombine
| Wide
[@@deriving sexp]
let sequence kind n =
let start = Incr.Var.create 0 in
let incr =
match kind with
| Recombine ->
Sequence.fold (Sequence.range 0 n) ~init:(Incr.Var.watch start) ~f:(fun incr _i ->
let a = incr >>| Int.succ in
let b = incr >>| Int.succ in
Incr.map2 a b ~f:( + ))
| Trivial ->
Sequence.fold (Sequence.range 0 n) ~init:(Incr.Var.watch start) ~f:(fun incr _i ->
incr >>| Int.succ)
| Wide ->
let double l =
List.concat_map l ~f:(fun i ->
let a = i >>| Int.succ in
let b = i >>| Int.succ in
[ a; b ])
in
let spread =
Sequence.fold
(Sequence.range 0 n)
~init:[ Incr.Var.watch start ]
~f:(fun incr_list _ -> double incr_list)
in
List.reduce_balanced_exn ~f:(Incr.map2 ~f:( + )) spread
in
start, incr
;;
let sequence_raw kind n =
let input, output =
let input, output = sequence kind n in
input, Incr.observe output
in
fun () ->
let open Infix in
input := !input + 1;
Incr.stabilize ();
ignore (Obs.value_exn output : int)
;;
let sequence_without_change kind n =
let output =
let _input, output = sequence kind n in
Incr.observe output
in
fun () ->
Incr.stabilize ();
ignore (Obs.value_exn output : int)
;;
let%bench_fun "Recombine 50" = sequence_raw Recombine 50
let%bench_fun "Trivial 50" = sequence_raw Trivial 50
let%bench_fun "Wide 5" = sequence_raw Wide 5
let%bench_fun "Wide 10" = sequence_raw Wide 10
let%bench_fun "50 (just stabilize)" = sequence_without_change Recombine 50
(*
Each iteration of "trivial 50" updates 50 incremental nodes.
Each iteration of "recombine 50" updates ~150 nodes.
Each iteration of "wide K" updates about 3 * 2^K nodes.
Dividing out times per run shows that each node update takes somewhere between 15 and
50 nanoseconds.
{v
┌─────────────────────────────────┬──────────────┬─────────┬────────────┐
│ Name │ Time/Run │ mWd/Run │ Percentage │
├─────────────────────────────────┼──────────────┼─────────┼────────────┤
│ [linear.ml] Recombine 50 │ 6_925.04ns │ │ 3.96% │
│ [linear.ml] Trivial 50 │ 729.76ns │ │ 0.42% │
│ [linear.ml] Wide 5 │ 5_059.74ns │ │ 2.90% │
│ [linear.ml] Wide 10 │ 174_702.44ns │ -0.81w │ 100.00% │
│ [linear.ml] 50 (just stabilize) │ 36.94ns │ │ 0.02% │
└─────────────────────────────────┴──────────────┴─────────┴────────────┘
v} *)
let%expect_test "stats" =
let stats = unstage (Stats.reporter ()) in
stats ();
[%expect
{|
((recomputed 0)
(changed 0)
(created 0))
|}];
let run = sequence_raw Recombine 50 in
stats ();
[%expect
{|
((recomputed 0)
(changed 0)
(created 151))
|}];
run ();
stats ();
[%expect
{|
((recomputed 151)
(changed 151)
(created 0))
|}];
run ();
stats ();
[%expect
{|
((recomputed 151)
(changed 151)
(created 0))
|}];
run ();
stats ();
[%expect
{|
((recomputed 151)
(changed 151)
(created 0))
|}]
;;