Skip to content

Commit 43a682d

Browse files
committed
reanalyze: add parallel processing for CMT file analysis
Add support for parallel processing of CMT files during dead code and exception analysis using OCaml 5 Domains. Features: - New -parallel N flag: process files using N domains (0 = sequential) - -parallel -1: auto-detect number of CPU cores - New -timing flag: report internal timing breakdown by phase - New benchmark infrastructure for performance testing The parallelization targets the CMT file processing phase, which is the main bottleneck (typically 75-80% of analysis time). The analysis and reporting phases remain sequential as they require merged cross-file data. Signed-Off-By: Cursor AI <noreply@cursor.com>
1 parent cc55edd commit 43a682d

File tree

15 files changed

+550
-111
lines changed

15 files changed

+550
-111
lines changed

Makefile

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,16 @@ test: lib ninja
172172
test-analysis: lib ninja
173173
make -C tests/analysis_tests clean test
174174

175+
test-reanalyze: lib ninja
176+
make -C tests/analysis_tests/tests-reanalyze/deadcode test
177+
178+
test-reanalyze-parallel: lib ninja
179+
make -C tests/analysis_tests/tests-reanalyze/deadcode test-parallel
180+
181+
# Benchmark parallel analysis on larger codebase (COPIES=N for more files)
182+
benchmark-reanalyze: lib ninja
183+
make -C tests/analysis_tests/tests-reanalyze/deadcode-benchmark benchmark COPIES=$(or $(COPIES),50)
184+
175185
test-tools: lib ninja
176186
make -C tests/tools_tests clean test
177187

@@ -244,4 +254,4 @@ dev-container:
244254

245255
.DEFAULT_GOAL := build
246256

247-
.PHONY: yarn-install build ninja rewatch compiler lib artifacts bench test test-analysis test-tools test-syntax test-syntax-roundtrip test-gentype test-rewatch test-all playground playground-compiler playground-test playground-cmijs playground-release format checkformat clean-ninja clean-rewatch clean-compiler clean-lib clean-gentype clean-tests clean dev-container
257+
.PHONY: yarn-install build ninja rewatch compiler lib artifacts bench test test-analysis test-reanalyze test-reanalyze-parallel benchmark-reanalyze test-tools test-syntax test-syntax-roundtrip test-gentype test-rewatch test-all playground playground-compiler playground-test playground-cmijs playground-release format checkformat clean-ninja clean-rewatch clean-compiler clean-lib clean-gentype clean-tests clean dev-container

analysis/reanalyze/src/Cli.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,9 @@ let excludePaths = ref ([] : string list)
2121

2222
(* test flag: shuffle file order to verify order-independence *)
2323
let testShuffle = ref false
24+
25+
(* parallel processing: number of domains to use (0 = sequential) *)
26+
let parallel = ref 0
27+
28+
(* timing: report internal timing of analysis phases *)
29+
let timing = ref false

analysis/reanalyze/src/DeadValue.ml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -384,9 +384,10 @@ let traverseStructure ~config ~decls ~refs ~file_deps ~cross_file ~file ~doTypes
384384
modulePath.path @ [FileContext.module_name_tagged file]
385385
in
386386
let name = id |> Ident.name |> Name.create in
387-
name
388-
|> DeadException.add ~config ~decls ~file ~path ~loc
389-
~strLoc:structureItem.str_loc ~moduleLoc:modulePath.loc;
387+
ignore
388+
(DeadException.add ~config ~decls ~file ~path ~loc
389+
~strLoc:structureItem.str_loc ~moduleLoc:modulePath.loc
390+
name);
390391
None
391392
| _ -> None
392393
in

analysis/reanalyze/src/Exception.ml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
open DeadCommon
22

3-
(** Per-file mutable builder for exception values during AST processing *)
43
type values_builder = (Name.t, Exceptions.t) Hashtbl.t
4+
(** Per-file mutable builder for exception values during AST processing *)
55

6-
(** Merged immutable table for cross-file lookups *)
76
type values_table = (string, (Name.t, Exceptions.t) Hashtbl.t) Hashtbl.t
7+
(** Merged immutable table for cross-file lookups *)
88

99
let create_values_builder () : values_builder = Hashtbl.create 15
1010

@@ -174,8 +174,8 @@ module Event = struct
174174
(exnSet, exnTable)
175175
end
176176

177-
(** Per-file mutable builder for checks during AST processing *)
178177
type checks_builder = check list ref
178+
(** Per-file mutable builder for checks during AST processing *)
179179

180180
and check = {
181181
events: Event.t list;
@@ -248,8 +248,7 @@ let traverseAst ~file ~values_builder ~checks_builder () =
248248
| None -> (
249249
match modulePath with
250250
| [] -> None
251-
| _ :: restModulePath ->
252-
path |> findLocalPath ~modulePath:restModulePath)
251+
| _ :: restModulePath -> path |> findLocalPath ~modulePath:restModulePath)
253252
in
254253
let exceptionsOfPatterns patterns =
255254
patterns
@@ -537,12 +536,12 @@ let traverseAst ~file ~values_builder ~checks_builder () =
537536
fun (structure : Typedtree.structure) ->
538537
process_structure ModulePath.initial structure
539538

540-
(** Result of processing a single file *)
541539
type file_result = {
542540
module_name: string;
543541
values_builder: values_builder;
544542
checks: check list;
545543
}
544+
(** Result of processing a single file *)
546545

547546
let processStructure ~file ~values_builder ~checks_builder
548547
(structure : Typedtree.structure) =

0 commit comments

Comments
 (0)