Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
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
let cache_size = 1 lsl 14 type cache_bucket = int (* 0 to cache_size - 1 *) module Writer = struct open Buf.Write (* The writer cache carries slightly more state than the reader cache, since the writer must make decisions about which slot to use. (The reader just follows the choices made by the writer) *) type t = { cache : int array; cache_date : int array; (* when an entry was added to the cache (used for eviction) *) cache_next : cache_bucket array; (* last time we saw this entry, which entry followed it? *) 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 (* Pick the least recently used of two slots, selected by two different hashes. *) 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 (* cache miss *) log_new_location ~index:pos; let bucket = if cache.cache_date.(hash1) < cache.cache_date.(hash2) then hash1 else hash2 in (* Printf.printf "miss %05d %016x\n%!" bucket slot; (*" %016x\n%!" bucket slot;*) *) 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 = (* Printf.printf "hit %d\n" hit; *) 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 (* correct prediction *) (* Printf.printf "pred %d %d\n" pred_bucket ncorrect; *) if ncorrect = 255 then begin (* overflow: code a new prediction block *) 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 (* incorrect prediction *) 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; } let create () = { cache_loc = Array.make cache_size 0; cache_pred = Array.make cache_size 0; last_backtrace = [| |] } 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 = assert (common_pfx_len <= Array.length cache.last_backtrace); 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 -> (* cache hit, 0 prediction *) let bbuf = put_bbuf bbuf pos cache_loc.(bucket) in predict bucket bbuf (pos + 1) (i - 1) 0 | 1 -> (* cache hit, 1 prediction *) let bbuf = put_bbuf bbuf pos cache_loc.(bucket) in predict bucket bbuf (pos + 1) (i - 1) 1 | 2 -> (* cache hit, N prediction *) let ncorrect = get_8 b in let bbuf = put_bbuf bbuf pos cache_loc.(bucket) in predict bucket bbuf (pos + 1) (i - 1) ncorrect | _ -> (* cache miss *) 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 let (bbuf, pos) = decode 0 cache.last_backtrace common_pfx_len nencoded in cache.last_backtrace <- bbuf; (bbuf, pos) 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) (* hitN *) else if codeword land 3 = 3 then ignore (get_64 b) (* miss *) 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