Skip to content
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 (david.klaftenegger@it.uu.se) and
%% Kjell Winblad (kjell.winblad@it.uu.se)


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.