1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
module Context = Tezos_protocol_environment.Context
type t = {
total : int;
keys : int;
dirs : int;
degrees : int list;
depths : int list;
sizes : int list;
}
let min_max (l : int list) =
let rec loop l mn mx =
match l with
| [] -> (mn, mx)
| x :: tl ->
let mn = min mn x in
let mx = max mx x in
loop tl mn mx
in
loop l max_int ~-1
let pp fmtr {total; keys; dirs; degrees = _; depths = _; sizes} =
let min_size, max_size = min_max sizes in
Format.fprintf
fmtr
"{ total = %d; keys = %d ; dirs = %d; sizes in [%d; %d] degrees = ...; \
depths = _}"
total
keys
dirs
min_size
max_size
let empty_stats () =
{total = 0; keys = 0; dirs = 0; degrees = []; depths = []; sizes = []}
let tree_statistics key_map =
let open Io_helpers.Key_map in
let nodes = ref 0 in
let keys = ref 0 in
let dirs = ref 0 in
let rec loop tree depth degrees depths sizes =
match tree with
| Leaf size ->
incr nodes ;
incr keys ;
(degrees, depth :: depths, size :: sizes)
| Node map ->
let degree = Io_helpers.Key_map.String_map.cardinal map in
let degrees = degree :: degrees in
incr nodes ;
incr dirs ;
Io_helpers.Key_map.String_map.fold
(fun _ tree (degrees, depths, sizes) ->
loop tree (depth + 1) degrees depths sizes)
map
(degrees, depths, sizes)
in
let degrees, depths, sizes = loop key_map 0 [] [] [] in
{total = !nodes; keys = !keys; dirs = !dirs; degrees; depths; sizes}
let load_tree context key =
let open Lwt_syntax in
Context.fold
context
key
~order:`Sorted
~init:Io_helpers.Key_map.empty
~f:(fun path t tree ->
let+ o = Context.Tree.to_value t in
match o with
| Some bytes ->
let len = Bytes.length bytes in
Io_helpers.Key_map.insert path len tree
| None -> tree)
let context_statistics base_dir context_hash =
let open Lwt_syntax in
let context, index =
Io_helpers.load_context_from_disk base_dir context_hash
in
let* tree = load_tree context [] in
let* () = Tezos_context.Context.close index in
Lwt.return (tree_statistics tree)
let array_of_int_list (l : int list) = Array.map float_of_int (Array.of_list l)
let plot_histograms pdf_file {degrees; depths; sizes; _} =
let open Plot in
let degree =
let points =
degrees |> List.to_seq |> Seq.map float_of_int |> Seq.map r1
|> Data.of_seq
in
plot2
~title:"Tree degree distribution"
~xaxis:"degree"
~yaxis:"freq"
[Histogram.hist ~bins:50 ~points ()]
in
let depth =
let points =
depths |> List.to_seq |> Seq.map float_of_int |> Seq.map r1 |> Data.of_seq
in
plot2
~title:"Key depth distribution"
~xaxis:"depth"
~yaxis:"freq"
[Histogram.hist ~bins:50 ~points ()]
in
let size =
let points =
sizes |> List.to_seq |> Seq.map float_of_int |> Seq.map r1 |> Data.of_seq
in
plot2
~title:"Data size distribution"
~xaxis:"size"
~yaxis:"freq"
[Histogram.hist ~bins:50 ~points ()]
in
let plots = [|[|Some degree; Some depth; Some size|]|] in
run_matrix ~target:(pdf ~cm_size:(30.0, 20.0) ~pdf_file ()) plots