Skip to content

Commit 89e55d4

Browse files
committed
[herd] More efficient computation of atomic load X stores pairs
We take inspiration from the efficient computation of register read-from (see PR #1704): atomic stores are ordered according to (extended by iico) program order and an atomic load is paired with the closest atomic write that follows it.
1 parent 971d0bb commit 89e55d4

File tree

3 files changed

+103
-51
lines changed

3 files changed

+103
-51
lines changed

herd/mem.ml

Lines changed: 66 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -770,24 +770,36 @@ let map_loc_find loc m =
770770
try U.LocEnv.find loc m
771771
with Not_found -> []
772772

773+
(* Event set ordered by to (generalised) program order *)
774+
775+
module
776+
EvtSetByPo
777+
(I:sig val es : S.event_structure end) =
778+
struct
779+
780+
let is_before_strict = U.is_before_strict I.es
781+
782+
include Set.Make
783+
(struct
784+
785+
type t = E.event
786+
787+
let compare e1 e2 =
788+
if is_before_strict e1 e2 then -1
789+
else if is_before_strict e2 e1 then 1
790+
else
791+
let () =
792+
Printf.eprintf "Not ordered stores %a and %a\n" E.debug_event e1
793+
E.debug_event e2
794+
in
795+
assert false
796+
797+
end)
798+
end
799+
773800
let match_reg_events add_eq es csn =
774801
let loc_loads_stores = U.collect_reg_loads_stores es in
775-
let is_before_strict = U.is_before_strict es in
776-
let compare e1 e2 =
777-
if is_before_strict e1 e2 then -1
778-
else if is_before_strict e2 e1 then 1
779-
else
780-
let () =
781-
Printf.eprintf "Not ordered stores %a and %a\n" E.debug_event e1
782-
E.debug_event e2
783-
in
784-
assert false
785-
in
786-
let module StoreSet = Set.Make (struct
787-
type t = E.event
788-
789-
let compare = compare
790-
end) in
802+
let module StoreSet = EvtSetByPo(struct let es = es end) in
791803
let add wt rf (rfm, csn) = (S.RFMap.add wt rf rfm, add_eq rfm wt rf csn) in
792804
(* For all loads find the right store, the one "just before" the load *)
793805
U.LocEnv.fold
@@ -803,7 +815,7 @@ let match_reg_events add_eq es csn =
803815
(* Add the corresponding store for each load *)
804816
List.fold_left
805817
(fun k load ->
806-
let f e = is_before_strict e load in
818+
let f e = StoreSet.is_before_strict e load in
807819
let rf =
808820
match StoreSet.find_last_opt f stores with
809821
| Some store -> S.Store store
@@ -1672,37 +1684,43 @@ let get_rf_value test read =
16721684
(* Reconstruct load/store atomic pairs *)
16731685

16741686
let make_atomic_load_store es =
1675-
let all = E.atomics_of es.E.events in
1676-
let atms = U.collect_atomics es in
1677-
U.LocEnv.fold
1678-
(fun _loc atms k ->
1679-
let atms =
1680-
List.filter
1681-
(fun e -> not (E.is_load e && E.is_store e))
1682-
atms in (* get rid of C RMW *)
1683-
let rs,ws = List.partition E.is_load atms in
1684-
List.fold_left
1685-
(fun k r ->
1686-
let exp = E.is_explicit r in
1687-
List.fold_left
1688-
(fun k w ->
1689-
if
1690-
S.atomic_pair_allowed r w &&
1691-
U.is_before_strict es r w &&
1692-
E.is_explicit w = exp &&
1693-
not
1694-
(E.EventSet.exists
1695-
(fun e ->
1696-
E.is_explicit e = exp &&
1697-
U.is_before_strict es r e &&
1698-
U.is_before_strict es e w)
1699-
all)
1700-
then E.EventRel.add (r,w) k
1701-
else k)
1702-
k ws)
1703-
k rs)
1704-
atms E.EventRel.empty
1705-
1687+
let atms,spurious = U.collect_atomics es in
1688+
let module StoreSet = EvtSetByPo(struct let es = es end) in
1689+
let make_atomic_pairs es k =
1690+
let rs,ws = List.partition E.is_load es in
1691+
let stores = StoreSet.of_list ws in
1692+
List.fold_left
1693+
(fun k load ->
1694+
let f e = StoreSet.is_before_strict load e in
1695+
match StoreSet.find_first_opt f stores with
1696+
| None -> k (* No matching store (e.g. final load reserve) *)
1697+
| Some store ->
1698+
if S.atomic_pair_allowed load store then
1699+
E.EventRel.add (load,store) k
1700+
else k)
1701+
k rs in
1702+
let r1 =
1703+
List.map
1704+
(fun (_,m) ->
1705+
U.LocEnv.fold
1706+
(fun _loc es k ->
1707+
let exps,nexps = List.partition E.is_explicit es in
1708+
make_atomic_pairs exps @@ make_atomic_pairs nexps k)
1709+
m E.EventRel.empty)
1710+
atms |> E.EventRel.unions
1711+
and r2 =
1712+
let iico = es.E. intra_causality_data in
1713+
List.map
1714+
(fun e ->
1715+
if E.is_load e then
1716+
match
1717+
E.EventRel.succs iico e |> E.EventSet.as_singleton
1718+
with
1719+
| None -> assert false (* spurious updates are by pairs *)
1720+
| Some w -> E.EventRel.singleton (e,w)
1721+
else E.EventRel.empty)
1722+
spurious |> E.EventRel.unions in
1723+
E.EventRel.union r1 r2
17061724

17071725
(* Retrieve last store from rfmap *)
17081726
let get_max_store _test _es rfm loc =

herd/memUtils.ml

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,9 +387,31 @@ let lift_proc_info i evts =
387387
and collect_stores es = collect_by_loc es E.is_store
388388
and collect_loads_non_spec es = collect_by_loc es (fun e -> E.is_load e && not_speculated es e)
389389
and collect_stores_non_spec es = collect_by_loc es (fun e -> E.is_store e && not_speculated es e)
390-
and collect_atomics es = collect_by_loc es E.is_atomic
391390
and collect_reg_loads_stores es = collect_by_loc2 es E.is_reg_load_any E.is_reg_store_any
392391

392+
let collect_atomics es =
393+
let m,sp =
394+
E.EventSet.fold
395+
(fun e (m,sp as k) ->
396+
if E.is_atomic e then
397+
match E.proc_of e with
398+
| None ->
399+
if E.is_spurious e then (m,e::sp)
400+
else k
401+
| Some proc ->
402+
IntMap.update proc
403+
(fun old ->
404+
let m =
405+
match old with
406+
| None -> LocEnv.empty
407+
| Some m -> m in
408+
Some (LocEnv.accumulate (get_loc e) e m))
409+
m,sp
410+
else k)
411+
es.E.events (IntMap.empty,[]) in
412+
IntMap.bindings m,sp
413+
414+
393415
let partition_events es =
394416
let env =
395417
E.EventSet.fold

herd/memUtils.mli

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ module Make : functor (S: SemExtra.S) -> sig
7070
relation *)
7171
val make_fr : S.concrete -> S.event_rel -> S.event_rel
7272

73-
(* Mapping from locations *)
73+
(* Mapping from locations, a.k.a. location maps *)
7474
module LocEnv : MyMap.S with type key = S.location
7575

7676
(* Collect various events, indexed by location *)
@@ -85,7 +85,19 @@ module Make : functor (S: SemExtra.S) -> sig
8585
val collect_stores : S.event_structure -> S.event list LocEnv.t
8686
val collect_stores_non_spec : S.event_structure -> S.event list LocEnv.t
8787
val collect_loads_non_spec : S.event_structure -> S.event list LocEnv.t
88-
val collect_atomics : S.event_structure -> S.event list LocEnv.t
88+
89+
(*
90+
* Collect atomic effects indexed by threads and by locations.
91+
* When given an event structure as argument, the function
92+
* returns a pair [(maps,evts)], where:
93+
* + [maps] is a list of location maps, one per thread.
94+
* The values of this map are the atomic effects
95+
of the given thread.
96+
* + [evts] is the list of spurious (atomic) effects.
97+
*)
98+
99+
val collect_atomics :
100+
S.event_structure -> (Proc.t * S.event list LocEnv.t) list * S.event list
89101

90102
(* Partition by location *)
91103
val partition_events : S.event_set -> S.event_set list

0 commit comments

Comments
 (0)