Skip to content

Commit f493a87

Browse files
authored
Merge pull request #11362 from ocaml/concurrent-fiber-solver
Concurrent fiber solver
2 parents e31faae + 7b9c153 commit f493a87

File tree

5 files changed

+46
-33
lines changed

5 files changed

+46
-33
lines changed

otherlibs/stdune/src/hashtbl.ml

+2
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ struct
7575
|> List.sort ~compare:(fun (k, _) (k', _) -> Dyn.compare k k'))
7676
;;
7777

78+
let to_list t = foldi t ~init:[] ~f:(fun key v acc -> (key, v) :: acc)
79+
7880
let filteri_inplace t ~f =
7981
filter_map_inplace t ~f:(fun ~key ~data ->
8082
match f ~key ~data with

otherlibs/stdune/src/hashtbl_intf.ml

+1
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ module type S = sig
2121
val to_dyn : ('v -> Dyn.t) -> 'v t -> Dyn.t
2222
val filteri_inplace : 'a t -> f:(key:key -> data:'a -> bool) -> unit
2323
val length : _ t -> int
24+
val to_list : 'a t -> (key * 'a) list
2425
end

otherlibs/stdune/src/table.ml

+1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ let filteri_inplace (type input output) ((module T) : (input, output) t) ~f =
9696
;;
9797

9898
let length (type input output) ((module T) : (input, output) t) = T.H.length T.value
99+
let to_list (type input output) ((module T) : (input, output) t) = T.H.to_list T.value
99100

100101
module Multi = struct
101102
let cons t x v =

otherlibs/stdune/src/table.mli

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ val iter : (_, 'v) t -> f:('v -> unit) -> unit
4040
val filteri_inplace : ('a, 'b) t -> f:(key:'a -> data:'b -> bool) -> unit
4141
val length : (_, _) t -> int
4242
val values : (_, 'a) t -> 'a list
43+
val to_list : ('a, 'b) t -> ('a * 'b) list
4344

4445
module Multi : sig
4546
type ('k, 'v) t

src/dune_pkg/opam_solver.ml

+41-33
Original file line numberDiff line numberDiff line change
@@ -696,36 +696,38 @@ module Solver = struct
696696
might need, adding all of them to [sat_problem]. *)
697697
let build_problem context root_req sat ~dummy_impl =
698698
(* For each (iface, source) we have a list of implementations. *)
699-
let impl_cache = ref Input.Role.Map.empty in
699+
let impl_cache = Fiber_cache.create (module Input.Role) in
700700
let conflict_classes = Conflict_classes.create () in
701701
let+ () =
702702
let rec lookup_impl expand_deps role =
703-
match Input.Role.Map.find !impl_cache role with
704-
| Some s -> Fiber.return s
705-
| None ->
706-
let* clause, impls =
707-
Candidates.make_impl_clause sat context ~dummy_impl role
708-
in
709-
impl_cache := Input.Role.Map.set !impl_cache role clause;
710-
let+ () =
711-
Fiber.sequential_iter impls ~f:(fun { var = impl_var; impl } ->
712-
Conflict_classes.process conflict_classes impl_var impl;
713-
match expand_deps with
714-
| `No_expand -> Fiber.return ()
715-
| `Expand_and_collect_conflicts deferred ->
716-
Input.Impl.requires role impl
717-
|> Fiber.sequential_iter ~f:(fun (dep : Input.dependency) ->
718-
match dep.importance with
719-
| Ensure -> process_dep expand_deps impl_var dep
720-
| Prevent ->
721-
(* Defer processing restricting deps until all essential
722-
deps have been processed for the entire problem.
723-
Restricting deps will be processed later without
724-
recurring into their dependencies. *)
725-
deferred := (impl_var, dep) :: !deferred;
726-
Fiber.return ()))
727-
in
728-
clause
703+
let impls = ref [] in
704+
let* clause =
705+
Fiber_cache.find_or_add impl_cache role ~f:(fun () ->
706+
let+ clause, impls' =
707+
Candidates.make_impl_clause sat context ~dummy_impl role
708+
in
709+
impls := impls';
710+
clause)
711+
in
712+
let+ () =
713+
Fiber.parallel_iter !impls ~f:(fun { var = impl_var; impl } ->
714+
Conflict_classes.process conflict_classes impl_var impl;
715+
match expand_deps with
716+
| `No_expand -> Fiber.return ()
717+
| `Expand_and_collect_conflicts deferred ->
718+
Input.Impl.requires role impl
719+
|> Fiber.parallel_iter ~f:(fun (dep : Input.dependency) ->
720+
match dep.importance with
721+
| Ensure -> process_dep expand_deps impl_var dep
722+
| Prevent ->
723+
(* Defer processing restricting deps until all essential
724+
deps have been processed for the entire problem.
725+
Restricting deps will be processed later without
726+
recurring into their dependencies. *)
727+
deferred := (impl_var, dep) :: !deferred;
728+
Fiber.return ()))
729+
in
730+
clause
729731
and process_dep expand_deps user_var (dep : Input.dependency) : unit Fiber.t =
730732
(* Process a dependency of [user_var]:
731733
- find the candidate implementations to satisfy it
@@ -776,13 +778,12 @@ module Solver = struct
776778
restricting dependencies are irrelevant to solving the dependency
777779
problem. *)
778780
List.rev !conflicts
779-
|> Fiber.sequential_iter ~f:(fun (impl_var, dep) ->
781+
|> Fiber.parallel_iter ~f:(fun (impl_var, dep) ->
780782
process_dep `No_expand impl_var dep)
781783
(* All impl_candidates have now been added, so snapshot the cache. *)
782784
in
783-
let impl_clauses = !impl_cache in
784785
Conflict_classes.seal conflict_classes;
785-
impl_clauses
786+
impl_cache
786787
;;
787788

788789
(** [do_solve model req] finds an implementation matching the given
@@ -807,7 +808,8 @@ module Solver = struct
807808
*)
808809
let sat = Sat.create () in
809810
let dummy_impl = if closest_match then Some Input.Dummy else None in
810-
let+ impl_clauses = build_problem context root_req sat ~dummy_impl in
811+
let* impl_clauses = build_problem context root_req sat ~dummy_impl in
812+
let+ impl_clauses = Fiber_cache.to_table impl_clauses in
811813
(* Run the solve *)
812814
let decider () =
813815
(* Walk the current solution, depth-first, looking for the first
@@ -819,7 +821,7 @@ module Solver = struct
819821
then None (* Break cycles *)
820822
else (
821823
Table.set seen req true;
822-
match Input.Role.Map.find_exn impl_clauses req |> Candidates.state with
824+
match Table.find_exn impl_clauses req |> Candidates.state with
823825
| Unselected -> None
824826
| Undecided lit -> Some lit
825827
| Selected deps ->
@@ -841,7 +843,13 @@ module Solver = struct
841843
| false -> None
842844
| true ->
843845
(* Build the results object *)
844-
Some (Input.Role.Map.filter_map impl_clauses ~f:Candidates.selected)
846+
Some
847+
(Table.to_list impl_clauses
848+
|> List.filter_map ~f:(fun (key, v) ->
849+
match Candidates.selected v with
850+
| None -> None
851+
| Some v -> Some (key, v))
852+
|> Input.Role.Map.of_list_exn)
845853
;;
846854
end
847855

0 commit comments

Comments
 (0)