Skip to content

Commit 7919791

Browse files
committed
updated multicore lockfree
1 parent 34a776a commit 7919791

File tree

12 files changed

+432
-204
lines changed

12 files changed

+432
-204
lines changed

benchmarks/multicore-lockfree/ctrie-dune.inc

Lines changed: 0 additions & 16 deletions
This file was deleted.

benchmarks/multicore-lockfree/ctrie.ml

Lines changed: 0 additions & 117 deletions
This file was deleted.
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
module Ctrie = struct
2+
(* Concurrent, hash array mapped trie based on -
3+
Prokopec, A. et al. (2011)
4+
Cache-Aware Lock-Free Concurrent Hash Tries. Technical Report, 2011. *)
5+
6+
(* configuration parameters *)
7+
let shift = 5
8+
9+
(* data definition *)
10+
type node =
11+
| Empty
12+
| Cnode of { map : int ; nodes : (node Atomic.t) array }
13+
| Inode of { key : int ; values : int list ; delete : bool }
14+
15+
type t = node Atomic.t
16+
17+
(* helper functions *)
18+
19+
(* detect flag of key in map *)
20+
let flag k l _map =
21+
let i =
22+
(k lsr (l * shift))
23+
land
24+
((1 lsl shift) - 1) in
25+
i
26+
27+
(* check if flag is set *)
28+
let set i map =
29+
((1 lsl i) land map) <> 0
30+
31+
(* detect position in array *)
32+
let pos flag map =
33+
(Base.Int.popcount (((1 lsl flag) - 1) land map))
34+
35+
(* create empty map *)
36+
let empty () = Atomic.make Empty
37+
38+
(* insert key and value binding into map *)
39+
let rec insert_aux k v l t =
40+
match Atomic.get t with
41+
| Empty ->
42+
let i = flag k l 0 in
43+
let map = 1 lsl i in
44+
let nodes = [|
45+
(Atomic.make (Inode {key = k ; values = [v] ; delete = false}))
46+
|] in
47+
let new_node = Cnode { map ; nodes } in
48+
Atomic.compare_and_set t Empty new_node
49+
| Cnode { map ; nodes } as c ->
50+
let i = flag k l map in
51+
if (set i map) then begin
52+
let p = pos i map in
53+
insert_aux k v (l+1) nodes.(p)
54+
end else begin
55+
let map = (1 lsl i) lor (map) in
56+
let p = pos i map in
57+
let old_len = Array.length nodes in
58+
let new_nodes = Array.init (old_len + 1) (fun i ->
59+
if i < p then nodes.(i) else
60+
if i = p then
61+
Atomic.make (Inode {key = k; values = [v] ; delete = false})
62+
else
63+
nodes.(i-1)) in
64+
let new_node = Cnode { map ; nodes = new_nodes } in
65+
Atomic.compare_and_set t c new_node
66+
end
67+
| Inode { key ; values ; delete} as inode ->
68+
if key = k then begin
69+
let new_values = v :: values in
70+
let new_node = Inode { key ; values = new_values ; delete } in
71+
Atomic.compare_and_set t inode new_node
72+
end else begin
73+
let i = flag key l 0 in
74+
let ni = flag k l 0 in
75+
let map = (1 lsl i) lor 0 in
76+
let map = (1 lsl ni) lor map in
77+
let nodes =
78+
if (ni > i) then
79+
([|
80+
Atomic.make (Inode { key ; values ; delete }) ;
81+
Atomic.make (Inode { key = k ; values = [v] ; delete = false })
82+
|], true)
83+
else if (ni < i) then
84+
([|
85+
Atomic.make (Inode { key = k ; values = [v] ; delete = false }) ;
86+
Atomic.make (Inode { key ; values ; delete })
87+
|], true)
88+
else begin
89+
let i = flag key (l+1) 0 in
90+
let nmap = (1 lsl i) lor 0 in
91+
let nnodes = [|Atomic.make (Inode {key ; values; delete})|] in
92+
([|
93+
Atomic.make (Cnode { map = nmap ; nodes = nnodes })
94+
|], false)
95+
end in
96+
let (nodes, new_level) = nodes in
97+
let new_node = Cnode { map ; nodes } in
98+
Atomic.compare_and_set t inode new_node && new_level
99+
end
100+
101+
let rec insert k v t =
102+
if insert_aux k v 0 t then () else insert k v t
103+
104+
(* check if key in map *)
105+
let rec mem k l t =
106+
match Atomic.get t with
107+
| Empty -> false
108+
| Cnode { map ; nodes } ->
109+
let f = flag k l map in
110+
if (set f map) then begin
111+
let p = pos f map in
112+
mem k (l+1) nodes.(p)
113+
end else begin
114+
false
115+
end
116+
| Inode { key ; _ } -> if key = k then true else false
117+
118+
let mem k t = mem k 0 t
119+
end
120+
121+
module T = Domainslib.Task
122+
123+
let num_domains = try int_of_string Sys.argv.(1) with _ -> 4
124+
let num_elems = try int_of_string Sys.argv.(2) with _ -> 1000000
125+
let ins_ratio = try float_of_string Sys.argv.(3) with _ -> 0.5
126+
127+
let state_key = Domain.DLS.new_key Random.State.make_self_init in
128+
129+
let rand_int () =
130+
let state = Domain.DLS.get state_key in
131+
Random.State.int state 10000
132+
133+
let rand_float () =
134+
let state = Domain.DLS.get state_key in
135+
Random.State.float state 1.0
136+
137+
let work tree int =
138+
if rand_float () > ins_ratio then
139+
ignore (Ctrie.mem (rand_int ()) tree)
140+
else
141+
ignore (Ctrie.insert (rand_int ()) 0 tree)
142+
143+
let _ =
144+
let pool = T.setup_pool num_domains in
145+
let tree = Ctrie.empty () in
146+
let work = work tree in
147+
T.parallel_for ~start:0 ~finish:(num_elems - 1) ~body:work pool;
148+
T.teardown_pool pool

0 commit comments

Comments
 (0)