Skip to content

Instantly share code, notes, and snippets.

@sile
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sile/7a7ae89380b0e8cac28e to your computer and use it in GitHub Desktop.
Save sile/7a7ae89380b0e8cac28e to your computer and use it in GitHub Desktop.
Erlang/OTP 17.1でmapsを使用する場合の注意点 ref: http://qiita.com/sile/items/48f1268d2e03915ca479
-module(bench).
-export([bench/0]).
-spec bench() -> [Result] when
Result :: {module(), ElementSize::pos_integer(), InsertAverageNanoSeconds::non_neg_integer()}.
bench() ->
ElementSizeList = [1, 10, 100, 1000, 10000, 100000],
InputList = [shuffle(lists:seq(0, Size - 1)) || Size <- ElementSizeList],
ModuleList = [dict, gb_trees, maps],
lists:sort(
[do_bench(Module, Input) || Module <- ModuleList,
Input <- InputList]).
-spec do_bench(module(), [non_neg_integer()]) -> Result when
Result :: {module(), ElementSize::pos_integer(), InsertAverageNanoSeconds::non_neg_integer()}.
do_bench(Module, Input) ->
ElementSize = length(Input),
LoopCount = 100000 div ElementSize, % 一回のベンチマーク中の挿入操作の回数を等しくさせるために、ループ数で調整する
Empty = make_empty(Module),
Fun = get_insert_fun(Module),
{TotalMicroSeconds, _} =
timer:tc(fun () -> bench_loop(LoopCount, Empty, Fun, Input) end),
AverageNanoSeconds = round((TotalMicroSeconds * 1000) / 100000),
{Module, ElementSize, AverageNanoSeconds}.
-spec make_empty(module()) -> term().
make_empty(dict) -> dict:new();
make_empty(gb_trees) -> gb_trees:empty();
make_empty(maps) -> maps:new().
-spec get_insert_fun(module()) -> fun ((term(), term(), term()) -> term()).
get_insert_fun(dict) -> fun dict:store/3;
get_insert_fun(gb_trees) -> fun gb_trees:enter/3;
get_insert_fun(maps) -> fun maps:put/3.
-spec shuffle(list()) -> list().
shuffle(List) ->
[X||{_,X} <- lists:keysort(1, [{random:uniform(), N} || N <- List])].
-spec bench_loop(non_neg_integer(), term(), function(), [non_neg_integer()]) -> ok.
bench_loop(0, _, _, _) -> ok;
bench_loop(LoopCount, Empty, Fun, Input) ->
_ = lists:foldl(fun (N, Acc) -> Fun(N, N, Acc) end, Empty, Input),
bench_loop(LoopCount - 1, Empty, Fun, Input).
/* maps:get/2
* return value if key *matches* a key in the map
* exception bad_key if none matches
*/
int erts_maps_get(Eterm key, Eterm map, Eterm *value) {
Eterm *ks,*vs;
map_t *mp;
Uint n,i;
mp = (map_t*)map_val(map);
n = map_get_size(mp);
if (n == 0)
return 0;
ks = map_get_keys(mp);
vs = map_get_values(mp);
if (is_immed(key)) {
for( i = 0; i < n; i++) {
if (ks[i] == key) {
*value = vs[i];
return 1;
}
}
}
for( i = 0; i < n; i++) {
if (EQ(ks[i], key)) {
*value = vs[i];
return 1;
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment