Source file backtrace_codec.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
let cache_size = 1 lsl 14
type cache_bucket = int
module Writer = struct
open Buf.Write
type t = {
cache : int array;
cache_date : int array;
cache_next : cache_bucket array;
mutable next_verify_ix : int;
}
let create () =
{ cache = Array.make cache_size 0;
cache_date = Array.make cache_size 0;
cache_next = Array.make cache_size 0;
next_verify_ix = 4242 }
let max_length = 4096
let put_backtrace cache b ~alloc_id ~callstack ~callstack_len ~log_new_location =
let max_entry = 2 + 8 in
let limit = b.pos + max_length - max_entry in
let put_hit b bucket ncorrect =
match ncorrect with
| 0 -> put_16 b (bucket lsl 2)
| 1 -> put_16 b ((bucket lsl 2) lor 1)
| n -> put_16 b ((bucket lsl 2) lor 2); put_8 b n in
let rec code_no_prediction predictor pos ncodes =
if pos < 0 || b.pos > limit then
ncodes
else begin
let mask = cache_size - 1 in
let slot = callstack.(pos) in
let hash1 = ((slot * 0x4983723) lsr 11) land mask in
let hash2 = ((slot * 0xfdea731) lsr 21) land mask in
if cache.cache.(hash1) = slot then begin
code_cache_hit predictor hash1 pos ncodes
end else if cache.cache.(hash2) = slot then begin
code_cache_hit predictor hash2 pos ncodes
end else begin
log_new_location ~index:pos;
let bucket =
if cache.cache_date.(hash1) < cache.cache_date.(hash2) then
hash1
else
hash2 in
cache.cache.(bucket) <- slot;
cache.cache_date.(bucket) <- alloc_id;
cache.cache_next.(predictor) <- bucket;
put_16 b ((bucket lsl 2) lor 3);
put_64 b (Int64.of_int slot);
code_no_prediction bucket (pos-1) (ncodes + 1)
end
end
and code_cache_hit predictor hit pos ncodes =
cache.cache_date.(hit) <- alloc_id;
cache.cache_next.(predictor) <- hit;
code_with_prediction hit hit 0 (pos-1) (ncodes+1)
and code_with_prediction orig_hit predictor ncorrect pos ncodes =
assert (ncorrect < 256);
if pos < 0 || b.pos + 2 > limit then begin
put_hit b orig_hit ncorrect;
ncodes
end else begin
let slot = callstack.(pos) in
let pred_bucket = cache.cache_next.(predictor) in
if cache.cache.(pred_bucket) = slot then begin
if ncorrect = 255 then begin
put_hit b orig_hit ncorrect;
code_cache_hit predictor pred_bucket pos ncodes
end else begin
code_with_prediction orig_hit pred_bucket (ncorrect + 1) (pos-1) ncodes
end
end else begin
put_hit b orig_hit ncorrect;
code_no_prediction predictor pos ncodes
end
end in
code_no_prediction 0 callstack_len 0
let put_cache_verifier cache b =
let ix = cache.next_verify_ix in
cache.next_verify_ix <-
(cache.next_verify_ix + 5413) land (cache_size - 1);
put_16 b ix;
put_16 b cache.cache_next.(ix);
put_64 b (Int64.of_int cache.cache.(ix))
let put_dummy_verifier b =
put_16 b 0xffff;
put_16 b 0;
put_64 b 0L
end
module Reader = struct
open Buf.Read
type t = {
cache_loc : int array;
cache_pred : int array;
mutable last_backtrace : int array;
mutable last_backtrace_len : int;
}
let create () =
{ cache_loc = Array.make cache_size 0;
cache_pred = Array.make cache_size 0;
last_backtrace = [| |];
last_backtrace_len = 0; }
let[@inline never] realloc_bbuf bbuf pos (x : int) =
assert (pos = Array.length bbuf);
let new_size = Array.length bbuf * 2 in
let new_size = if new_size < 32 then 32 else new_size in
let new_bbuf = Array.make new_size x in
Array.blit bbuf 0 new_bbuf 0 pos;
new_bbuf
let[@inline] put_bbuf bbuf pos (x : int) =
if pos < Array.length bbuf then begin
Array.unsafe_set bbuf pos x;
bbuf
end else
realloc_bbuf bbuf pos x
let get_backtrace ({ cache_loc ; cache_pred; _ } as cache) b ~nencoded ~common_pfx_len =
let rec decode pred bbuf pos = function
| 0 -> (bbuf, pos)
| i ->
let codeword = get_16 b in
let bucket = codeword lsr 2 and tag = codeword land 3 in
cache_pred.(pred) <- bucket;
begin match tag with
| 0 ->
let bbuf = put_bbuf bbuf pos cache_loc.(bucket) in
predict bucket bbuf (pos + 1) (i - 1) 0
| 1 ->
let bbuf = put_bbuf bbuf pos cache_loc.(bucket) in
predict bucket bbuf (pos + 1) (i - 1) 1
| 2 ->
let ncorrect = get_8 b in
let bbuf = put_bbuf bbuf pos cache_loc.(bucket) in
predict bucket bbuf (pos + 1) (i - 1) ncorrect
| _ ->
let lit = Int64.to_int (get_64 b) in
cache_loc.(bucket) <- lit;
let bbuf = put_bbuf bbuf pos lit in
decode bucket bbuf (pos + 1) (i - 1)
end
and predict pred bbuf pos i = function
| 0 -> decode pred bbuf pos i
| n ->
let pred' = cache_pred.(pred) in
let bbuf = put_bbuf bbuf pos cache_loc.(pred') in
predict pred' bbuf (pos + 1) i (n-1) in
if common_pfx_len <= cache.last_backtrace_len then begin
let (bbuf, pos) = decode 0 cache.last_backtrace common_pfx_len nencoded in
cache.last_backtrace <- bbuf;
cache.last_backtrace_len <- pos;
(bbuf, pos)
end else begin
let (_bbuf, _pos) = decode 0 [| |] 0 nencoded in
(cache.last_backtrace, cache.last_backtrace_len)
end
let skip_backtrace _cache b ~nencoded ~common_pfx_len:_ =
for _ = 1 to nencoded do
let codeword = get_16 b in
if codeword land 3 = 2 then
ignore (get_8 b)
else if codeword land 3 = 3 then
ignore (get_64 b)
done
let check_cache_verifier cache b =
let ix = get_16 b in
let pred = get_16 b in
let value = get_64 b in
if ix <> 0xffff then
(0 <= ix && ix < Array.length cache.cache_loc &&
cache.cache_pred.(ix) = pred &&
cache.cache_loc.(ix) = Int64.to_int value)
else
true
let skip_cache_verifier b =
let _ix = get_16 b in
let _pred = get_16 b in
let _value = get_64 b in
()
end