Skip to content

Commit 3542c07

Browse files
committed
Use Multicore_magic.instantaneous_domain_index in Accumulator
1 parent 40ad1fb commit 3542c07

File tree

8 files changed

+52
-62
lines changed

8 files changed

+52
-62
lines changed

dune-project

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
(domain-local-timeout
3838
(>= 1.0.0))
3939
(multicore-magic
40-
(>= 2.0.0))
40+
(>= 2.1.0))
4141
(domain_shims
4242
(and
4343
(>= 0.1.0)
@@ -65,7 +65,7 @@
6565
(kcas
6666
(= :version))
6767
(multicore-magic
68-
(>= 2.0.0))
68+
(>= 2.1.0))
6969
(domain-local-await
7070
(and
7171
(>= 1.0.0)

kcas.opam

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ depends: [
1818
"backoff" {>= "0.1.0"}
1919
"domain-local-await" {>= "1.0.0"}
2020
"domain-local-timeout" {>= "1.0.0"}
21-
"multicore-magic" {>= "2.0.0"}
21+
"multicore-magic" {>= "2.1.0"}
2222
"domain_shims" {>= "0.1.0" & with-test}
2323
"alcotest" {>= "1.7.0" & with-test}
2424
"mdx" {>= "2.3.0" & with-test}
@@ -40,3 +40,6 @@ build: [
4040
]
4141
dev-repo: "git+https://github.com/ocaml-multicore/kcas.git"
4242
doc: "https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/"
43+
pin-depends: [
44+
[ "multicore-magic.dev" "git+https://github.com/ocaml-multicore/multicore-magic#dd9d8928fba7ab5dedef612a96bf01bd17cbd275" ]
45+
]

kcas.opam.template

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
doc: "https://ocaml-multicore.github.io/kcas/doc/kcas/Kcas/"
2+
pin-depends: [
3+
[ "multicore-magic.dev" "git+https://github.com/ocaml-multicore/multicore-magic#dd9d8928fba7ab5dedef612a96bf01bd17cbd275" ]
4+
]

kcas_data.opam

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ bug-reports: "https://github.com/ocaml-multicore/kcas/issues"
1515
depends: [
1616
"dune" {>= "3.8"}
1717
"kcas" {= version}
18-
"multicore-magic" {>= "2.0.0"}
18+
"multicore-magic" {>= "2.1.0"}
1919
"domain-local-await" {>= "1.0.0" & with-test}
2020
"domain_shims" {>= "0.1.0" & with-test}
2121
"mtime" {>= "2.0.0" & with-test}

src/kcas_data/accumulator.ml

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,48 @@
11
open Kcas
22

3-
let n_way_max = Domain.recommended_domain_count () |> Bits.ceil_pow_2
4-
let n_way_default = n_way_max |> Int.min 8
5-
6-
type t = int Loc.t array
7-
8-
let make ?n_way n =
9-
let n_way =
10-
match n_way with
11-
| None -> n_way_default
12-
| Some n_way -> n_way |> Int.min n_way_max |> Bits.ceil_pow_2
3+
(** TODO:
4+
- Limit array length to [Domain.recommended_domain_count ()].
5+
- CPUs do not necessarily have power of two number of cores. *)
6+
7+
type t = { mutable cache : int Loc.t array; truth : int Loc.t array Loc.t }
8+
9+
let make n =
10+
let cs = Loc.make_array ~padded:true ~mode:Mode.lock_free 1 0 in
11+
Loc.set (Array.unsafe_get cs 0) n;
12+
let truth = Loc.make ~padded:true cs in
13+
Multicore_magic.copy_as_padded { cache = cs; truth }
14+
15+
let[@inline never] get_self a i cs n =
16+
let add_cs = Loc.make_array ~padded:true ~mode:Mode.lock_free n 0 in
17+
let new_cs =
18+
Array.init (n * 2) @@ fun i ->
19+
if i < n then Array.unsafe_get add_cs i else Array.unsafe_get cs (i - n)
1320
in
14-
let a = Loc.make_array ~padded:true ~mode:Mode.lock_free n_way 0 in
15-
Loc.set (Array.unsafe_get a 0) n;
16-
a
17-
18-
let n_way_of = Array.length
21+
if Loc.compare_and_set a.truth cs new_cs then a.cache <- new_cs;
22+
Array.unsafe_get cs (i land (n - 1))
1923

20-
let get_self a =
21-
let h = (Domain.self () :> int) in
22-
(* TODO: Consider mixing the bits of [h] to get better distribution *)
23-
Array.unsafe_get a (h land (Array.length a - 1))
24+
let[@inline] get_self a =
25+
let i = Multicore_magic.instantaneous_domain_index () in
26+
let cs = a.cache in
27+
let n = Array.length cs in
28+
if i < n then Array.unsafe_get cs i else get_self a i cs n
2429

2530
module Xt = struct
2631
let add ~xt a n = if n <> 0 then Xt.fetch_and_add ~xt (get_self a) n |> ignore
2732
let incr ~xt a = Xt.incr ~xt (get_self a)
2833
let decr ~xt a = Xt.decr ~xt (get_self a)
2934

30-
let rec get ~xt a s i =
31-
let s = s + Xt.get ~xt (Array.unsafe_get a i) in
32-
if i = 0 then s else get ~xt a s (i - 1)
35+
let rec get_rec ~xt cs s i =
36+
let s = s + Xt.get ~xt (Array.unsafe_get cs i) in
37+
if i = 0 then s else get_rec ~xt cs s (i - 1)
3338

3439
let get ~xt a =
35-
let i = Array.length a - 1 in
36-
let s = Xt.get ~xt (Array.unsafe_get a i) in
37-
if i = 0 then s else get ~xt a s (i - 1)
40+
let cs = Xt.get ~xt a.truth in
41+
let cs_old = a.cache in
42+
if cs != cs_old then a.cache <- cs;
43+
let i = Array.length cs - 1 in
44+
let s = Xt.get ~xt (Array.unsafe_get cs i) in
45+
if i = 0 then s else get_rec ~xt cs s (i - 1)
3846

3947
let set ~xt a n = add ~xt a (n - get ~xt a)
4048
end

src/kcas_data/accumulator.mli

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,8 @@ open Kcas
1010
type t
1111
(** The type of a scalable accumulator. *)
1212

13-
val make : ?n_way:int -> int -> t
14-
(** [make n] returns a new accumulator whose initial value is [n].
15-
16-
The optional [n_way] argument can be used to specify a desired level of
17-
parallelism, i.e. maximum number of non-interfering parallel updates. The
18-
default value is chosen to strike a balance between scalability and memory
19-
use and a given value may be adjusted by the implementation. *)
20-
21-
val n_way_of : t -> int
22-
(** [n_way_of a] returns the maximum number of non-interfering parallel updates
23-
supported by the accumulator [a].
24-
25-
{b NOTE}: The returned value may not be the same as given to {!make}. *)
13+
val make : int -> t
14+
(** [make n] returns a new accumulator whose initial value is [n]. *)
2615

2716
(** {1 Compositional interface} *)
2817

src/kcas_data/hashtbl.ml

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ module HashedType = struct
127127
hash == HashedType.hash && equal == HashedType.equal
128128
end
129129

130-
let create ?hashed_type ?min_buckets ?max_buckets ?n_way () =
130+
let create ?hashed_type ?min_buckets ?max_buckets () =
131131
let min_buckets =
132132
match min_buckets with
133133
| None -> min_buckets_default
@@ -144,13 +144,12 @@ let create ?hashed_type ?min_buckets ?max_buckets ?n_way () =
144144
| Some hashed_type -> HashedType.unpack hashed_type
145145
and pending = Nothing
146146
and buckets = Loc.make_array min_buckets Assoc.Nil
147-
and length = Accumulator.make ?n_way 0 in
147+
and length = Accumulator.make 0 in
148148
Loc.set t
149149
(Multicore_magic.copy_as_padded
150150
{ pending; length; buckets; hash; equal; min_buckets; max_buckets });
151151
t
152152

153-
let n_way_of t = Accumulator.n_way_of (Loc.get t).length
154153
let min_buckets_of t = (Loc.get t).min_buckets
155154
let max_buckets_of t = (Loc.get t).max_buckets
156155

@@ -444,12 +443,12 @@ let to_seq t =
444443
let to_seq_keys t = to_seq t |> Seq.map fst
445444
let to_seq_values t = to_seq t |> Seq.map snd
446445

447-
let of_seq ?hashed_type ?min_buckets ?max_buckets ?n_way xs =
448-
let t = create ?hashed_type ?min_buckets ?max_buckets ?n_way () in
446+
let of_seq ?hashed_type ?min_buckets ?max_buckets xs =
447+
let t = create ?hashed_type ?min_buckets ?max_buckets () in
449448
Seq.iter (fun (k, v) -> replace t k v) xs;
450449
t
451450

452-
let rebuild ?hashed_type ?min_buckets ?max_buckets ?n_way t =
451+
let rebuild ?hashed_type ?min_buckets ?max_buckets t =
453452
let record = ref (Obj.magic ()) and length = ref 0 in
454453
let snapshot = snapshot ~length ~record t in
455454
let r = !record in
@@ -462,8 +461,6 @@ let rebuild ?hashed_type ?min_buckets ?max_buckets ?n_way t =
462461
match max_buckets with
463462
| None -> Int.max min_buckets r.max_buckets
464463
| Some c -> Int.max min_buckets c |> Int.min hi_buckets |> Bits.ceil_pow_2
465-
and n_way =
466-
match n_way with None -> Accumulator.n_way_of r.length | Some n -> n
467464
in
468465
let is_same_hashed_type =
469466
match hashed_type with
@@ -474,14 +471,14 @@ let rebuild ?hashed_type ?min_buckets ?max_buckets ?n_way t =
474471
let t = Loc.make ~padded:true (Obj.magic ()) in
475472
let pending = Nothing
476473
and buckets = Array.map Loc.make snapshot
477-
and length = Accumulator.make ~n_way length in
474+
and length = Accumulator.make length in
478475
Loc.set t
479476
@@ Multicore_magic.copy_as_padded
480477
{ r with pending; length; buckets; min_buckets; max_buckets };
481478
t
482479
end
483480
else
484-
let t = create ?hashed_type ~min_buckets ~max_buckets ~n_way () in
481+
let t = create ?hashed_type ~min_buckets ~max_buckets () in
485482
snapshot |> Array.iter (Assoc.iter_rev (add t));
486483
t
487484

src/kcas_data/hashtbl.mli

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ val create :
4343
?hashed_type:'k hashed_type ->
4444
?min_buckets:int ->
4545
?max_buckets:int ->
46-
?n_way:int ->
4746
unit ->
4847
('k, 'v) t
4948
(** [create ()] returns a new empty hash table.
@@ -55,8 +54,6 @@ val create :
5554
- The default [max_buckets] is the minimum of [1 lsl 30] and suitably
5655
adjusted [Sys.max_array_length] and a given [max_buckets] may be adjusted
5756
by the implementation.
58-
- The [n_way] argument is passed to the internal {!Accumulator} used to keep
59-
track of the number of bindings.
6057
6158
Hash tables are automatically internally resized. *)
6259

@@ -76,16 +73,10 @@ val max_buckets_of : ('k, 'v) t -> int
7673
7774
{b NOTE}: The returned value may not be the same as given to {!create}. *)
7875

79-
val n_way_of : ('k, 'v) t -> int
80-
(** [n_way_of t] returns the maximum number of non-interfering parallel updates
81-
allowed by the internal {!Accumulator} used to keep track of the number of
82-
bindings in the hash table [t]. *)
83-
8476
val of_seq :
8577
?hashed_type:'k hashed_type ->
8678
?min_buckets:int ->
8779
?max_buckets:int ->
88-
?n_way:int ->
8980
('k * 'v) Seq.t ->
9081
('k, 'v) t
9182
(** [of_seq assoc] creates a new hash table from the given association sequence
@@ -138,7 +129,6 @@ val rebuild :
138129
?hashed_type:'k hashed_type ->
139130
?min_buckets:int ->
140131
?max_buckets:int ->
141-
?n_way:int ->
142132
('k, 'v) t ->
143133
('k, 'v) t
144134
(** [rebuild t] returns a copy of the given hash table [t] optionally rehashing

0 commit comments

Comments
 (0)