Skip to content

Commit d8441c6

Browse files
committed
Allocate location ids in descending order
This should typically lead to slightly improved performance as it is typical that locations closer to the root of a data structure are allocated before locations further from the root. So, when a data structure is traversed starting from the root, the resuling splay tree should be right leaning and slightly faster to construct and traverse from left to right.
1 parent c858cb1 commit d8441c6

File tree

6 files changed

+37
-22
lines changed

6 files changed

+37
-22
lines changed

src/kcas.ml

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ let fenceless_set = Atomic.set
2020
module Backoff = Backoff
2121

2222
module Id = struct
23-
let neg_id = Atomic.make Int.min_int
24-
let neg_id () = Atomic.fetch_and_add neg_id 1
25-
let nat_id = Atomic.make 0
26-
let nat_id () = Atomic.fetch_and_add nat_id 1
23+
let neg_id = Atomic.make (-1)
24+
let neg_ids n = Atomic.fetch_and_add neg_id (-n) [@@inline]
25+
let neg_id () = neg_ids 1 [@@inline]
26+
let nat_id = Atomic.make Int.max_int
27+
let nat_ids n = Atomic.fetch_and_add nat_id (-n) [@@inline]
28+
let nat_id () = nat_ids 1 [@@inline]
2729
end
2830

2931
module Action : sig
@@ -376,6 +378,15 @@ module Loc = struct
376378
in
377379
make_loc state id
378380

381+
let make_array ?(mode = Mode.obstruction_free) n after =
382+
assert (0 <= n);
383+
let state = new_state after
384+
and id =
385+
(if mode == Mode.obstruction_free then Id.nat_ids n else Id.neg_ids n)
386+
- (n - 1)
387+
in
388+
Array.init n @@ fun i -> make_loc state (id + i)
389+
379390
let get_id loc = loc.id [@@inline]
380391
let get loc = eval (Atomic.get (as_atomic loc))
381392

src/kcas.mli

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ module Loc : sig
6969
in rare cases where a location is updated frequently and obstruction-free
7070
read-only accesses would almost certainly suffer from interference. *)
7171

72+
val make_array : ?mode:Mode.t -> int -> 'a -> 'a t array
73+
(** [make_array n initial] creates an array of [n] new shared memory locations
74+
with the [initial] value. *)
75+
7276
val get_mode : 'a t -> Mode.t
7377
(** [get_mode r] returns the operating mode of the shared memory location
7478
[r]. *)

src/kcas_data/accumulator.ml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ let make ?n_way n =
1111
| None -> n_way_default
1212
| Some n_way -> n_way |> Int.min n_way_max |> Bits.ceil_pow_2
1313
in
14-
Array.init n_way (fun i -> Loc.make (if i = 0 then n else 0))
14+
let a = Loc.make_array ~mode:Mode.lock_free n_way 0 in
15+
Loc.set (Array.unsafe_get a 0) n;
16+
a
1517

1618
let n_way_of = Array.length
1719

src/kcas_data/hashtbl.ml

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,6 @@ module HashedType = struct
106106
hash == HashedType.hash && equal == HashedType.equal
107107
end
108108

109-
let make_bucket _ = Loc.make []
110-
111109
let create ?hashed_type ?min_buckets ?max_buckets ?n_way () =
112110
let min_buckets =
113111
match min_buckets with
@@ -123,8 +121,9 @@ let create ?hashed_type ?min_buckets ?max_buckets ?n_way () =
123121
| None -> (Stdlib.Hashtbl.seeded_hash (Random.bits ()), ( = ))
124122
| Some hashed_type -> HashedType.unpack hashed_type
125123
and pending = Loc.make Nothing
126-
and length = Accumulator.make ?n_way 0
127-
and buckets = Loc.make @@ Array.init min_buckets make_bucket in
124+
and buckets = Loc.make [||]
125+
and length = Accumulator.make ?n_way 0 in
126+
Loc.set buckets @@ Loc.make_array min_buckets [];
128127
{ pending; length; buckets; hash; equal; min_buckets; max_buckets }
129128

130129
let n_way_of t = Accumulator.n_way_of t.length
@@ -173,8 +172,7 @@ module Xt = struct
173172
| Nothing -> ()
174173
| Rehash { state; new_capacity; new_buckets } -> (
175174
let new_buckets =
176-
get_or_alloc new_buckets @@ fun () ->
177-
Array.init new_capacity make_bucket
175+
get_or_alloc new_buckets @@ fun () -> Loc.make_array new_capacity []
178176
in
179177
let old_buckets = Xt.exchange ~xt t.buckets new_buckets in
180178
let hash = t.hash and mask = new_capacity - 1 in
@@ -244,8 +242,7 @@ module Xt = struct
244242
Retry.unless (0 <= Loc.fenceless_get state);
245243
let new_capacity = Array.length old_buckets in
246244
let new_buckets =
247-
get_or_alloc new_buckets @@ fun () ->
248-
Array.init new_capacity make_bucket
245+
get_or_alloc new_buckets @@ fun () -> Loc.make_array new_capacity []
249246
in
250247
let filter_map_a_few_buckets ~xt =
251248
let i = Xt.fetch_and_add ~xt state (-batch_size) in
@@ -404,11 +401,12 @@ let rebuild ?hashed_type ?min_buckets ?max_buckets ?n_way t =
404401
| None -> true
405402
| Some hashed_type -> HashedType.is_same_as t.hash t.equal hashed_type
406403
and length = !length in
407-
if is_same_hashed_type && min_buckets <= length && length <= max_buckets then
404+
if is_same_hashed_type && min_buckets <= length && length <= max_buckets then (
408405
let pending = Loc.make Nothing
409-
and length = Accumulator.make ~n_way length
410-
and buckets = Loc.make @@ Array.map Loc.make snapshot in
411-
{ t with pending; length; buckets; min_buckets; max_buckets }
406+
and buckets = Loc.make [||]
407+
and length = Accumulator.make ~n_way length in
408+
Loc.set buckets @@ Array.map Loc.make snapshot;
409+
{ t with pending; length; buckets; min_buckets; max_buckets })
412410
else
413411
let t = create ?hashed_type ~min_buckets ~max_buckets ~n_way () in
414412
snapshot

src/kcas_data/queue.ml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ type 'a t = {
66
front : 'a Elems.t Loc.t;
77
}
88

9-
let alloc ~back ~middle ~front =
9+
let alloc ~front ~middle ~back =
1010
(* We allocate locations in specific order to make most efficient use of the
1111
splay-tree based transaction log. *)
12-
let back = Loc.make back
12+
let front = Loc.make front
1313
and middle = Loc.make middle
14-
and front = Loc.make front in
14+
and back = Loc.make back in
1515
{ back; middle; front }
1616

17-
let create () = alloc ~back:Elems.empty ~middle:Elems.empty ~front:Elems.empty
17+
let create () = alloc ~front:Elems.empty ~middle:Elems.empty ~back:Elems.empty
1818

1919
let copy q =
2020
let tx ~xt = (Xt.get ~xt q.front, Xt.get ~xt q.middle, Xt.get ~xt q.back) in

test/benchmark.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ let make_kCAS k =
1616
if k > 0 then
1717
let a = Loc.make 0 in
1818
loop (k - 1) (Op.make_cas a 0 1 :: out1) (Op.make_cas a 1 0 :: out2)
19-
else (out1, out2)
19+
else (List.rev out1, List.rev out2)
2020
in
2121

2222
loop k [] []

0 commit comments

Comments
 (0)