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

ETS Fixed Elements Benchmark #11

Open
wants to merge 2 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
25 changes: 25 additions & 0 deletions bench/ets_fixed_elements/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
ERLC_OPTS =

SRCD = src
EBIND = ebin

ERLF = $(wildcard $(SRCD)/*.erl)
BEAMF = $(patsubst $(SRCD)/%.erl,$(EBIND)/%.beam,$(ERLF))

.PHONY: all bench clean

all: bench

bench: $(BEAMF)

$(EBIND)/%.beam: $(SRCD)/%.erl
erlc $(ERLC_OPTS) -o$(EBIND) $<

$(BEAMF): | $(EBIND)

$(EBIND):
mkdir -p $(EBIND)

clean:
$(RM) -rf $(EBIND)

81 changes: 81 additions & 0 deletions bench/ets_fixed_elements/src/ets_fixed_elements.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
-module(ets_fixed_elements).

-export([bench_args/2, run/3]).


%% Description: Inserts small number of fixed keys many times into ets
%% table in parallel. It test ets with set table type and write and
%% read concurrency enabled; and etsmp. See etsmp.erl for a
%% description of etsmp.
%%
%% Authors: David Klaftenegger ([email protected]) and
%% Kjell Winblad ([email protected])


bench_args(Version, _) ->
NrOfOperations =
case Version of
short -> 500000;
intermediate -> 5000000;
long -> 50000000
end,
TableImpels = [ets, etsmp],
[[NrOfOperations, TableImpel] || TableImpel <- TableImpels].


run([NrOfOperations, TableImpel| _], _, _) ->
NrOfWorkers = erlang:system_info(schedulers),
par_insert(NrOfOperations, 1024, NrOfWorkers, TableImpel).


%% Count = how many inserts
%% Max = maximum number of DIFFERENT inserts
%% WorkerCount = number of parallel inserts
par_insert(Count, Max, WorkerCount, TableImpel) ->
{Table, Workers} = setup(Count, Max, WorkerCount, TableImpel),
par_insert(Workers),
TableImpel:delete(Table),
ok.

%% start workers and wait for workers to finish
par_insert(Workers) ->
par_insert(Workers, []).
par_insert([], Running) ->
wait_for(Running);
par_insert([Next | Waiting], Running) ->
Next ! worker_start,
par_insert(Waiting, [Next | Running]).

%% wait for start signal, insert into table & notify parent when done
insert_and_msg(Start, End, Max, Table, Parent, TableImpel) ->
random:seed(now()),
Src = array:from_list([X||{_,X} <- lists:sort([ {random:uniform(), N} || N <- lists:seq(0,Max+1)])]),
receive worker_start -> ok end,
insert(Start, End, Max, Table, Src, TableImpel),
Parent ! {self(), worker_done},
ok.

wait_for([]) -> ok;
wait_for([Worker | Workers]) ->
receive {Worker, worker_done} -> ok end,
wait_for(Workers),
ok.

insert(Count, Count, _Max, _Table, _Src,_) -> ok;
insert(Num, Count, Max, Table, Src, TableImpel) ->
TableImpel:insert(Table, {array:get((Num rem Max)+1, Src), ignored}),
insert(Num+1, Count, Max, Table, Src, TableImpel).

setup(Count, Max, WorkerCount, TableImpel) ->
Table = TableImpel:new(?MODULE, [set, public, {read_concurrency, true}, {write_concurrency, true}]),
setup(Count, Max, WorkerCount, Table, 0, [], TableImpel).

setup(_Count, _Max, _WorkerCount, Table, _WorkerCount, Workers, _TableImpel) ->
{Table, Workers};
setup(Count, Max, WorkerCount, Table, Started, Workers, TableImpel) ->
MainProcess = self(),
Range = Count div WorkerCount,
Start = Started*Range,
End = Start+Range,
Workers2 = [spawn(fun() -> insert_and_msg(Start, End, Max, Table, MainProcess, TableImpel) end) | Workers],
setup(Count, Max, WorkerCount, Table, Started+1, Workers2, TableImpel).
99 changes: 99 additions & 0 deletions bench/ets_fixed_elements/src/etsmp.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
-module(etsmp).

-compile(export_all).

new(_,_) ->
new().

new() ->
NrOfSchedulers = erlang:system_info(schedulers),
NrOfSubTables = prime_greater_or_equal_than(NrOfSchedulers),
AllocateETSFun =
fun() ->
ets:new(test_table,
[set,
public,
{write_concurrency,true},
{read_concurrency,true}])
end,
lists:foldl(fun(Index, Array) ->
array:set(Index, AllocateETSFun(), Array)
end,
array:new(NrOfSubTables),
lists:seq(0, NrOfSubTables -1)).

delete(EtsmID) ->
lists:foreach(fun(EtsID) ->
ets:delete(EtsID)
end,
array:to_list(EtsmID)).

insert(EtsmID, Tuple) ->
HashValue = erlang:phash2(element(1,Tuple), array:size(EtsmID)),
SubTable = array:get(HashValue, EtsmID),
ets:insert(SubTable, Tuple).

delete(EtsmID, Key) ->
HashValue = erlang:phash2(Key, array:size(EtsmID)),
SubTable = array:get(HashValue, EtsmID),
ets:delete(SubTable, Key).

lookup(EtsmID, Key) ->
HashValue = erlang:phash2(Key, array:size(EtsmID)),
SubTable = array:get(HashValue, EtsmID),
ets:lookup(SubTable, Key).


prime_greater_or_equal_than(Number) ->
case Number =< 2 of
true ->
2;
false ->
prime_greater_or_equal_than(Number, 3, [2])
end.

prime_greater_or_equal_than(Number, NextNumber, PrimesSoFar) ->
IsPrime =
lists:all(
fun(Prime) ->
(NextNumber rem Prime) =/= 0
end,
PrimesSoFar),
case IsPrime of
true ->
case Number =< NextNumber of
true ->
NextNumber;
false ->
prime_greater_or_equal_than(
Number,
NextNumber + 1,
PrimesSoFar ++ [NextNumber])
end;
false ->
prime_greater_or_equal_than(
Number,
NextNumber + 1,
PrimesSoFar)
end.





test() ->
EtsmID = new(),
insert(EtsmID, {1}),
insert(EtsmID, {2}),
insert(EtsmID, {3}),
[{1}] = lookup(EtsmID, 1),
[{2}] = lookup(EtsmID, 2),
[{3}] = lookup(EtsmID, 3),
delete(EtsmID, 1),
delete(EtsmID, 2),
delete(EtsmID, 3),
[] = lookup(EtsmID, 1),
[] = lookup(EtsmID, 2),
[] = lookup(EtsmID, 3),
delete(EtsmID),
ok.