Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lock-free map bench #181

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions benchmarks/multicore-lockfree/bag-dune.inc

This file was deleted.

78 changes: 73 additions & 5 deletions benchmarks/multicore-lockfree/dune
Original file line number Diff line number Diff line change
@@ -1,5 +1,73 @@
(include hash-dune.inc)
(include wsqueue-dune.inc)
(include bag-dune.inc)
(include msqueue-dune.inc)
(include list-dune.inc)
(executable
(name test_bag)
(modules test_bag)
(libraries lockfree))

(executable
(name test_bag_multicore)
(modules test_bag_multicore)
(libraries lockfree))

(executable
(name test_list)
(modules test_list)
(libraries lockfree))

(executable
(name test_list_multicore)
(modules test_list_multicore)
(libraries lockfree))

(executable
(name test_hash)
(modules test_hash)
(libraries lockfree))

(executable
(name test_hash_multicore)
(modules test_hash_multicore)
(libraries lockfree))

(executable
(name test_msqueue)
(modules test_msqueue)
(libraries lockfree))

(executable
(name test_msqueue_multicore)
(modules test_msqueue_multicore)
(libraries lockfree))

(executable
(name test_wsqueue)
(modules test_wsqueue)
(libraries lockfree))

(executable
(name test_wsqueue_multicore)
(modules test_wsqueue_multicore)
(libraries lockfree))

(executable
(name test_ctrie)
(modules test_ctrie)
(libraries base))

(executable
(name test_ctrie_multicore)
(modules test_ctrie_multicore)
(libraries base domainslib))

(alias (name multibench_parallel)
(deps test_bag.exe
test_list.exe
test_hash.exe
test_msqueue.exe
test_wsqueue.exe
test_ctrie.exe
test_bag_multicore.exe
test_list_multicore.exe
test_hash_multicore.exe
test_msqueue_multicore.exe
test_wsqueue_multicore.exe
test_ctrie_multicore.exe))
11 changes: 0 additions & 11 deletions benchmarks/multicore-lockfree/hash-dune.inc

This file was deleted.

11 changes: 0 additions & 11 deletions benchmarks/multicore-lockfree/list-dune.inc

This file was deleted.

11 changes: 0 additions & 11 deletions benchmarks/multicore-lockfree/msqueue-dune.inc

This file was deleted.

141 changes: 141 additions & 0 deletions benchmarks/multicore-lockfree/test_ctrie.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
module Ctrie = struct
(* Concurrent, hash array mapped trie based on -
Prokopec, A. et al. (2011)
Cache-Aware Lock-Free Concurrent Hash Tries. Technical Report, 2011. *)

(* configuration parameters *)
let shift = 5

(* data definition *)
type node =
| Empty
| Cnode of { map : int ; nodes : (node Atomic.t) array }
| Inode of { key : int ; values : int list ; delete : bool }

type t = node Atomic.t

(* helper functions *)

(* detect flag of key in map *)
let flag k l _map =
let i =
(k lsr (l * shift))
land
((1 lsl shift) - 1) in
i

(* check if flag is set *)
let set i map =
((1 lsl i) land map) <> 0

(* detect position in array *)
let pos flag map =
(Base.Int.popcount (((1 lsl flag) - 1) land map))

(* create empty map *)
let empty () = Atomic.make Empty

(* insert key and value binding into map *)
let rec insert_aux k v l t =
match Atomic.get t with
| Empty ->
let i = flag k l 0 in
let map = 1 lsl i in
let nodes = [|
(Atomic.make (Inode {key = k ; values = [v] ; delete = false}))
|] in
let new_node = Cnode { map ; nodes } in
Atomic.compare_and_set t Empty new_node
| Cnode { map ; nodes } as c ->
let i = flag k l map in
if (set i map) then begin
let p = pos i map in
insert_aux k v (l+1) nodes.(p)
end else begin
let map = (1 lsl i) lor (map) in
let p = pos i map in
let old_len = Array.length nodes in
let new_nodes = Array.init (old_len + 1) (fun i ->
if i < p then nodes.(i) else
if i = p then
Atomic.make (Inode {key = k; values = [v] ; delete = false})
else
nodes.(i-1)) in
let new_node = Cnode { map ; nodes = new_nodes } in
Atomic.compare_and_set t c new_node
end
| Inode { key ; values ; delete} as inode ->
if key = k then begin
let new_values = v :: values in
let new_node = Inode { key ; values = new_values ; delete } in
Atomic.compare_and_set t inode new_node
end else begin
let i = flag key l 0 in
let ni = flag k l 0 in
let map = (1 lsl i) lor 0 in
let map = (1 lsl ni) lor map in
let nodes =
if (ni > i) then
([|
Atomic.make (Inode { key ; values ; delete }) ;
Atomic.make (Inode { key = k ; values = [v] ; delete = false })
|], true)
else if (ni < i) then
([|
Atomic.make (Inode { key = k ; values = [v] ; delete = false }) ;
Atomic.make (Inode { key ; values ; delete })
|], true)
else begin
let i = flag key (l+1) 0 in
let nmap = (1 lsl i) lor 0 in
let nnodes = [|Atomic.make (Inode {key ; values; delete})|] in
([|
Atomic.make (Cnode { map = nmap ; nodes = nnodes })
|], false)
end in
let (nodes, new_level) = nodes in
let new_node = Cnode { map ; nodes } in
Atomic.compare_and_set t inode new_node && new_level
end

let rec insert k v t =
if insert_aux k v 0 t then () else insert k v t

(* check if key in map *)
let rec mem k l t =
match Atomic.get t with
| Empty -> false
| Cnode { map ; nodes } ->
let f = flag k l map in
if (set f map) then begin
let p = pos f map in
mem k (l+1) nodes.(p)
end else begin
false
end
| Inode { key ; _ } -> if key = k then true else false

let mem k t = mem k 0 t
end

let num_elems = try int_of_string Sys.argv.(1) with _ -> 10_000_000
let ins_percent = try int_of_string Sys.argv.(2) with _ -> 50

let state_key = Domain.DLS.new_key Random.State.make_self_init

let rand_int n =
let state = Domain.DLS.get state_key in
Random.State.int state n

let work tree _ =
if rand_int 100 >= ins_percent then
ignore (Ctrie.mem (rand_int 10000) tree)
else
ignore (Ctrie.insert (rand_int 10000) 0 tree)

let _ =
let tree = Ctrie.empty () in
let work = work tree in
for i = 0 to (num_elems - 1) do
work i
done
Loading