%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 1996-2016. 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_dbn_meters). -export([ start/0, local_start/0, distr_start/1, start/3 ]). -record(simple,{key,val=0}). -define(key,1). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Configuration and start start() -> local_start(), distr_start(nodes()). local_start() -> start(one_ram_only,[node()],some_meters()), start(one_disc_only,[node()],some_meters()). distr_start([]) -> local_only; distr_start(OtherNodes) when is_list(OtherNodes) -> start(ram_and_ram,[node()|OtherNodes],some_meters()), start(disc_and_disc,[node()|OtherNodes],some_meters()). start(Config,Nodes,Meters) -> Attrs = record_info(fields,simple), Schema = [{name,simple},{type,set},{attributes,Attrs}] ++ config(Config,Nodes), L = '====================', io:format("~n~p dbn_meters: ~p ~p~nSchema = ~p.~n~n",[L,Config,L,Schema]), ok = mnesia:delete_schema(Nodes), ok = mnesia:create_schema(Nodes), rpc:multicall(Nodes, mnesia, start, []), {atomic,_} = mnesia:create_table(Schema), lists:foreach(fun report_meter/1,Meters), {atomic, ok} = mnesia:delete_table(simple), rpc:multicall(Nodes, mnesia, stop, []), ok. config(one_ram_only,[Single|_]) -> [{ram_copies,[Single]}]; config(ram_and_ram,[Master|[Slave|_]]) -> [{ram_copies,[Master,Slave]}]; config(one_disc_only,[Single|_]) -> [{disc_copies,[Single]}]; config(disc_and_disc,[Master|[Slave|_]]) -> [{disc_copies,[Master,Slave]}]; config(Config,Nodes) -> io:format(" Config ~p not supported or too few nodes ~p given~n",[Config,Nodes]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% The various DBN meters some_meters() -> [create, open_safe_read, open_dirty_read, get_int, open_update, put_int, put_int_and_copy, dirty_put_int_and_copy, start_trans, commit_one_update, delete, dirty_delete ]. report_meter(Meter) -> Times = 100, Micros = repeat_meter(Meter,{atomic,{0,ignore}},Times) div Times, io:format("\t~-30w ~-10w nano seconds (mean of ~p repetitions)~n",[Meter,Micros,Times]). repeat_meter(_Meter,{atomic,{Micros,_Result}},0) -> Micros; repeat_meter(Meter,{atomic,{Micros,_Result}},Times) when Times > 0 -> repeat_meter(Meter,catch meter(Meter),Times-1) + Micros; repeat_meter(Meter,{aborted,Reason},Times) when Times > 0 -> io:format("\t~-20w\t,aborted, because ~p~n",[Meter,Reason]), 0; repeat_meter(Meter,{'EXIT',Reason},Times) when Times > 0 -> io:format("\t~-20w\tcrashed, because ~p~n",[Meter,Reason]), 0. meter(create) -> Key = 1, mnesia:transaction(fun() -> mnesia:delete({simple,Key}) end), Fun = fun() -> BeforeT = erlang:monotonic_time(), R = mnesia:write(#simple{key=Key}), AfterT = erlang:monotonic_time(), elapsed_time(BeforeT,AfterT,R) end, mnesia:transaction(Fun); meter(open_safe_read) -> Key = 2, mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end), Fun = fun() -> BeforeT = erlang:monotonic_time(), R = mnesia:read({simple,Key}), AfterT = erlang:monotonic_time(), elapsed_time(BeforeT,AfterT,R) end, mnesia:transaction(Fun); meter(open_dirty_read) -> Key = 21, mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end), Fun = fun() -> BeforeT = erlang:monotonic_time(), R = mnesia:dirty_read({simple,Key}), AfterT = erlang:monotonic_time(), elapsed_time(BeforeT,AfterT,R) end, mnesia:transaction(Fun); meter(get_int) -> Key = 3, mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end), Fun = fun() -> [Simple] = mnesia:read({simple,Key}), BeforeT = erlang:monotonic_time(), Int = Simple#simple.val, AfterT = erlang:monotonic_time(), elapsed_time(BeforeT,AfterT,Int) end, mnesia:transaction(Fun); meter(open_update) -> Key = 3, mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end), Fun = fun() -> BeforeT = erlang:monotonic_time(), R = mnesia:wread({simple,Key}), AfterT = erlang:monotonic_time(), elapsed_time(BeforeT,AfterT,R) end, mnesia:transaction(Fun); meter(put_int) -> Key = 4, mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end), Fun = fun() -> [Simple] = mnesia:wread({simple,Key}), BeforeT = erlang:monotonic_time(), R = Simple#simple{val=7}, AfterT = erlang:monotonic_time(), elapsed_time(BeforeT,AfterT,R) end, mnesia:transaction(Fun); meter(put_int_and_copy) -> Key = 5, mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end), Fun = fun() -> [Simple] = mnesia:wread({simple,Key}), BeforeT = erlang:monotonic_time(), Simple2 = Simple#simple{val=17}, R = mnesia:write(Simple2), AfterT = erlang:monotonic_time(), elapsed_time(BeforeT,AfterT,R) end, mnesia:transaction(Fun); meter(dirty_put_int_and_copy) -> Key = 55, mnesia:dirty_write(#simple{key=Key}), [Simple] = mnesia:dirty_read({simple,Key}), BeforeT = erlang:monotonic_time(), Simple2 = Simple#simple{val=17}, R = mnesia:dirty_write(Simple2), AfterT = erlang:monotonic_time(), {atomic,elapsed_time(BeforeT,AfterT,R)}; meter(start_trans) -> BeforeT = erlang:monotonic_time(), {atomic,AfterT} = mnesia:transaction(fun() -> erlang:monotonic_time() end), {atomic,elapsed_time(BeforeT,AfterT,ok)}; meter(commit_one_update) -> Key = 6, mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end), Fun = fun() -> [Simple] = mnesia:wread({simple,Key}), Simple2 = Simple#simple{val=27}, _R = mnesia:write(Simple2), erlang:monotonic_time() end, {atomic,BeforeT} = mnesia:transaction(Fun), AfterT = erlang:monotonic_time(), {atomic,elapsed_time(BeforeT,AfterT,ok)}; meter(delete) -> Key = 7, mnesia:transaction(fun() -> mnesia:write(#simple{key=Key}) end), Fun = fun() -> BeforeT = erlang:monotonic_time(), R = mnesia:delete({simple,Key}), AfterT = erlang:monotonic_time(), elapsed_time(BeforeT,AfterT,R) end, mnesia:transaction(Fun); meter(dirty_delete) -> Key = 75, mnesia:dirty_write(#simple{key=Key}), BeforeT = erlang:monotonic_time(), R = mnesia:dirty_delete({simple,Key}), AfterT = erlang:monotonic_time(), {atomic, elapsed_time(BeforeT,AfterT,R)}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Calculate the elapsed time elapsed_time(BeforeT,AfterT,Result) -> {erlang:convert_time_unit(AfterT-BeforeT, native, nano_seconds),Result}.