Skip to content

Commit 3b6eb4a

Browse files
committed
[src][state][cmt] add caching
This replaces the previous local cache in location dependencies computation.
1 parent bcd17f9 commit 3b6eb4a

File tree

4 files changed

+100
-26
lines changed

4 files changed

+100
-26
lines changed

src/state/cmt.ml

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
module Cache = struct
2+
(** O(1) addition and retrieval *)
3+
4+
type ('k, 'v) t =
5+
{ store : ('k, 'v) Hashtbl.t
6+
(** filepath -> cmi_cmt_infos *)
7+
; capacity : int (** n <= capacity *)
8+
; mutable hit : int
9+
; mutable miss : int
10+
}
11+
12+
let create capacity =
13+
{ store = Hashtbl.create capacity
14+
; capacity
15+
; hit = 0
16+
; miss = 0
17+
}
18+
19+
let find_opt (cache : ('k, 'v) t) (key : 'k) : 'v option =
20+
let res = Hashtbl.find_opt cache.store key in
21+
if Option.is_some res then cache.hit <- cache.hit + 1
22+
else (cache.miss <- cache.miss + 1);
23+
res
24+
25+
let add cache key value =
26+
if Hashtbl.length cache.store = cache.capacity then
27+
Hashtbl.reset cache.store;
28+
Hashtbl.replace cache.store key value
29+
30+
end
31+
32+
let read_no_cache filepath =
33+
match Cmt_format.read filepath with
34+
| exception _ -> Result.error (filepath ^ ": error reading file")
35+
| _, None -> Result.error (filepath ^ ": cmt_infos not found")
36+
| cmi_infos, Some cmt_infos ->
37+
Result.ok (cmi_infos, cmt_infos)
38+
39+
type cmi_cmt_infos = Cmi_format.cmi_infos option * Cmt_format.cmt_infos
40+
41+
let cache_cmt : ((string * string), (string * cmi_cmt_infos)) Cache.t = Cache.create 64
42+
43+
let read filepath =
44+
let comp_unit = Utils.Filepath.unit filepath in
45+
let ext = Filename.extension filepath in
46+
match Cache.find_opt cache_cmt (ext, comp_unit) with
47+
| Some (fp, res) when String.equal fp filepath -> Result.ok res
48+
| _ ->
49+
read_no_cache filepath
50+
|> Result.map (fun cmi_cmt_infos ->
51+
Cache.add cache_cmt (ext, comp_unit) (filepath, cmi_cmt_infos);
52+
cmi_cmt_infos)
53+
54+
let find_cached_from_comp_unit comp_unit ext =
55+
Cache.find_opt cache_cmt (ext, comp_unit)
56+
|> Option.map snd
57+
58+
let cached_cmti comp_unit =
59+
find_cached_from_comp_unit comp_unit ".cmti"
60+
61+
let cached_cmt comp_unit =
62+
find_cached_from_comp_unit comp_unit ".cmt"
63+
64+
let print_cache_stats () =
65+
print_endline (Printf.sprintf "CMT CACHE : hit = %i ; miss = %i"
66+
cache_cmt.hit cache_cmt.miss)

src/state/cmt.mli

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
type cmi_cmt_infos = Cmi_format.cmi_infos option * Cmt_format.cmt_infos
2+
3+
val read : string -> (cmi_cmt_infos, string) Result.t
4+
5+
val cached_cmti : string -> cmi_cmt_infos option
6+
7+
val cached_cmt : string -> cmi_cmt_infos option
8+
9+
val print_cache_stats : unit -> unit

src/state/file_infos.ml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,9 @@ let empty = {
4747
let init_from_cm_file cm_file =
4848
if not (Sys.file_exists cm_file) then Result.error (cm_file ^ ": file not found")
4949
else
50-
match Cmt_format.read cm_file with
51-
| exception _ -> Result.error (cm_file ^ ": error reading file")
52-
| _, None -> Result.error (cm_file ^ ": cmt_infos not found")
53-
| cmi_infos, Some cmt_infos ->
50+
match Cmt.read cm_file with
51+
| Error _ as err -> err
52+
| Ok (cmi_infos, cmt_infos) ->
5453
let file_infos =
5554
init_from_all_cm_infos ~cm_file ~cmi_infos cmt_infos
5655
in

src/state/location_dependencies.ml

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,31 +20,32 @@ let fill_from_cmt_tbl uid_to_decl res_uid_to_loc =
2020
UidTbl.iter add_uid_loc uid_to_decl;
2121
res_uid_to_loc
2222

23-
let find_opt_external_uid_loc, clear_external_cache =
24-
let cache = Hashtbl.create 16 in
25-
let clear_external_cache () = Hashtbl.reset cache in
26-
let find_opt_external_uid_loc ~cm_paths = function
27-
| Shape.Uid.(Compilation_unit _ | Internal | Predef _) -> None
28-
| Item {comp_unit; _} as uid ->
23+
let find_opt_external_uid_loc ~cm_paths = function
24+
| Shape.Uid.(Compilation_unit _ | Internal | Predef _) -> None
25+
| Item {comp_unit; from; _} as uid ->
2926
let ( let* ) x f = Option.bind x f in
30-
let* cmt_uid_to_decl =
31-
match Hashtbl.find_opt cache comp_unit with
32-
| Some _ as cmt_uid_to_decl -> cmt_uid_to_decl
33-
| None ->
34-
let* cm_path =
35-
Utils.StringSet.elements cm_paths
36-
|> List.rev
37-
|> List.find_opt (fun path -> Utils.Filepath.unit path = comp_unit)
38-
in
39-
let* cmt_infos = Cmt_format.read cm_path |> snd in
40-
let cmt_uid_to_decl = cmt_infos.cmt_uid_to_decl in
41-
Hashtbl.add cache comp_unit cmt_uid_to_decl;
42-
Some cmt_uid_to_decl
27+
let cached =
28+
match from with
29+
| Unit_info.Intf -> Cmt.cached_cmti comp_unit
30+
| Unit_info.Impl -> Cmt.cached_cmt comp_unit
4331
in
32+
let read_from_path () =
33+
let* cm_path =
34+
Utils.StringSet.elements cm_paths
35+
|> List.rev
36+
|> List.find_opt (fun path -> Utils.Filepath.unit path = comp_unit)
37+
in
38+
Cmt.read cm_path |> Result.to_option
39+
in
40+
let* cmi_cmt_infos =
41+
match cached with
42+
| Some _ as some -> some
43+
| None -> read_from_path ()
44+
in
45+
let cmt_infos = snd cmi_cmt_infos in
46+
let cmt_uid_to_decl = cmt_infos.cmt_uid_to_decl in
4447
let* item_decl = UidTbl.find_opt cmt_uid_to_decl uid in
4548
loc_opt_of_item_decl item_decl
46-
in
47-
find_opt_external_uid_loc, clear_external_cache
4849

4950
let cmt_decl_dep_to_loc_dep ~cm_paths cmt_decl_dep uid_to_loc =
5051
let convert_pair (_dep_kind, uid_def, uid_decl) =
@@ -59,7 +60,6 @@ let cmt_decl_dep_to_loc_dep ~cm_paths cmt_decl_dep uid_to_loc =
5960
Some (def_loc, decl_loc)
6061
in
6162
let res = List.filter_map convert_pair cmt_decl_dep in
62-
clear_external_cache ();
6363
res
6464

6565
let init ~cm_paths cmt_infos cmti_uid_to_decl =

0 commit comments

Comments
 (0)