%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 1996-2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% %% -module(mnesia_cost). -export([go/0, go/1]). %% This code exercises the mnesia system and produces a bunch %% of measurements on what various things cost -define(TIMES, 1000). %% set to at least 1000 when running for real !! %% This is the record we perform all ops on in this test -record(item, {a = 1234, b = foobar, c = "1.2.3.4", d = {'Lennart', 'Hyland'}, e = true }). go() -> go([node() | nodes()]). go(Nodes) when hd(Nodes) == node() -> {ok, Out} = file:open("MNESIA_COST", write), put(out, Out), rpc:multicall(Nodes, mnesia, lkill, []), ok = mnesia:delete_schema(Nodes), ok = mnesia:create_schema(Nodes), rpc:multicall(Nodes, mnesia, start, []), TabDef = [{attributes, record_info(fields, item)}], {atomic, ok} = mnesia:create_table(item, TabDef), round("single ram copy", "no index"), {atomic, ok} = mnesia:add_table_index(item, #item.e), round("single ram copy", "One index"), {atomic, ok} = mnesia:add_table_index(item, #item.c), round("single ram copy", "Two indexes"), {atomic, ok} = mnesia:del_table_index(item, #item.e), {atomic, ok} = mnesia:del_table_index(item, #item.c), {atomic, ok} = mnesia:change_table_copy_type(item, node(), disc_copies), round("single disc copy", "no index"), {atomic, ok} = mnesia:change_table_copy_type(item, node(), ram_copies), case length(Nodes) of Len when Len < 2 -> format(" replication skipped. Too few nodes.", []); _Len -> N2 = lists:nth(2, Nodes), {atomic, ok} = mnesia:add_table_copy(item, N2, ram_copies), round("2 replicated ram copy", "no index") end, file:close(Out), erase(out), ok. round(Replication, Index) -> run(Replication, Index, [write], fun() -> mnesia:write(#item{}) end), run(Replication, Index, [read], fun() -> mnesia:read({item, 1234}) end), run(Replication, Index, [read, write], fun() -> mnesia:read({item, 1234}), mnesia:write(#item{}) end), run(Replication, Index, [wread, write], fun() -> mnesia:wread({item, 1234}), mnesia:write(#item{}) end), run(Replication, Index, [match, write, write, write], fun() -> mnesia:match_object({item, 1, '_', '_', '_', true}), mnesia:write(#item{a =1}), mnesia:write(#item{a =2}), mnesia:write(#item{a =3}) end). format(F, As) -> io:format(get(out), F, As). run(What, OtherInfo, Ops, F) -> run(t, What, OtherInfo, Ops, F). run(How, What, OtherInfo, Ops, F) -> T1 = erlang:monotonic_time(), statistics(runtime), do_times(How, ?TIMES, F), {_, RunTime} = statistics(runtime), T2 = erlang:monotonic_time(), RealTime = subtr(T1, T2), report(How, What, OtherInfo, Ops, RunTime, RealTime). report(t, What, OtherInfo, Ops, RunTime, RealTime) -> format("~s, ~s, transaction call ", [What, OtherInfo]), format("Ops is ", []), lists:foreach(fun(Op) -> format("~w-", [Op]) end, Ops), format("~n ~w/~w Millisecs/Trans ~w/~w MilliSecs/Operation ~n~n", [RunTime/?TIMES, RealTime/?TIMES, RunTime/(?TIMES*length(Ops)), RealTime/(?TIMES*length(Ops))]); report(dirty, What, OtherInfo, Ops, RunTime, RealTime) -> format("~s, ~s, dirty calls ", [What, OtherInfo]), format("Ops is ", []), lists:foreach(fun(Op) -> format("~w-", [Op]) end, Ops), format("~n ~w/~w Millisecs/Bunch ~w/~w MilliSecs/Operation ~n~n", [RunTime/?TIMES, RealTime/?TIMES, RunTime/(?TIMES*length(Ops)), RealTime/(?TIMES*length(Ops))]). subtr(Before, After) -> erlang:convert_time_unit(After-Before, native, milli_seconds). do_times(t, I, F) -> do_trans_times(I, F); do_times(dirty, I, F) -> do_dirty(I, F). do_trans_times(I, F) when I /= 0 -> {atomic, _} = mnesia:transaction(F), do_trans_times(I-1, F); do_trans_times(_,_) -> ok. do_dirty(I, F) when I /= 0 -> F(), do_dirty(I-1, F); do_dirty(_,_) -> ok.